summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/main/bugtraq/com/syntevo/bugtraq/BugtraqConfig.java2
-rw-r--r--src/main/distrib/data/defaults.properties61
-rw-r--r--src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java18
-rw-r--r--src/main/java/com/gitblit/git/PatchsetReceivePack.java4
-rw-r--r--src/main/java/com/gitblit/guice/WebModule.java12
-rw-r--r--src/main/java/com/gitblit/manager/AuthenticationManager.java77
-rw-r--r--src/main/java/com/gitblit/manager/GitblitManager.java16
-rw-r--r--src/main/java/com/gitblit/manager/IAuthenticationManager.java10
-rw-r--r--src/main/java/com/gitblit/manager/RepositoryManager.java12
-rw-r--r--src/main/java/com/gitblit/manager/ServicesManager.java9
-rw-r--r--src/main/java/com/gitblit/manager/UserManager.java6
-rw-r--r--src/main/java/com/gitblit/service/LuceneService.java5
-rw-r--r--src/main/java/com/gitblit/servlet/AccessDeniedServlet.java63
-rw-r--r--src/main/java/com/gitblit/servlet/RawServlet.java29
-rw-r--r--src/main/java/com/gitblit/tickets/BranchTicketService.java14
-rw-r--r--src/main/java/com/gitblit/transport/ssh/SshDaemon.java58
-rw-r--r--src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java52
-rw-r--r--src/main/java/com/gitblit/utils/CompressionUtils.java4
-rw-r--r--src/main/java/com/gitblit/utils/DiffUtils.java41
-rw-r--r--src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java14
-rw-r--r--src/main/java/com/gitblit/utils/JGitUtils.java24
-rw-r--r--src/main/java/com/gitblit/utils/RefLogUtils.java8
-rw-r--r--src/main/java/com/gitblit/utils/StringUtils.java17
-rw-r--r--src/main/java/com/gitblit/utils/X509Utils.java22
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BlamePage.java3
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java4
-rw-r--r--src/main/java/com/gitblit/wicket/pages/BlobPage.java3
-rw-r--r--src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java4
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ComparePage.java4
-rw-r--r--src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html9
-rw-r--r--src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java789
-rw-r--r--src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java4
-rw-r--r--src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java3
-rw-r--r--src/main/java/com/gitblit/wicket/pages/SessionPage.java7
-rw-r--r--src/main/java/com/gitblit/wicket/panels/HistoryPanel.java2
-rw-r--r--src/site/plugins_extensions.mkd10
-rw-r--r--src/site/setup_authentication.mkd10
-rw-r--r--src/test/config/test-gitblit.properties2
-rw-r--r--src/test/java/com/gitblit/tests/AuthenticationManagerTest.java675
-rw-r--r--src/test/java/com/gitblit/tests/DiffUtilsTest.java6
-rw-r--r--src/test/java/com/gitblit/tests/GitBlitSuite.java2
-rw-r--r--src/test/java/com/gitblit/tests/JschConfigTestSessionFactory.java1
-rw-r--r--src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java76
-rw-r--r--src/test/java/com/gitblit/tests/SshUnitTest.java8
-rw-r--r--src/test/java/com/gitblit/tests/StringUtilsTest.java2
45 files changed, 1734 insertions, 468 deletions
diff --git a/src/main/bugtraq/com/syntevo/bugtraq/BugtraqConfig.java b/src/main/bugtraq/com/syntevo/bugtraq/BugtraqConfig.java
index 7776e6fe..60b4ecc0 100644
--- a/src/main/bugtraq/com/syntevo/bugtraq/BugtraqConfig.java
+++ b/src/main/bugtraq/com/syntevo/bugtraq/BugtraqConfig.java
@@ -214,7 +214,7 @@ public final class BugtraqConfig {
}
finally {
rw.dispose();
- tw.release();
+ tw.close();
}
if (content == null) {
diff --git a/src/main/distrib/data/defaults.properties b/src/main/distrib/data/defaults.properties
index 0857ccf6..ae519a10 100644
--- a/src/main/distrib/data/defaults.properties
+++ b/src/main/distrib/data/defaults.properties
@@ -126,6 +126,28 @@ git.sshKeysManager = com.gitblit.transport.ssh.FileKeyManager
# SINCE 1.5.0
git.sshKeysFolder= ${baseFolder}/ssh
+# Use kerberos5 (GSS) authentication
+#
+# SINCE 1.7.0
+git.sshWithKrb5 = "false"
+
+# The path to a kerberos 5 keytab.
+#
+# SINCE 1.7.0
+git.sshKrb5Keytab = ""
+
+# The service principal name to be used for Kerberos5. The default is host/hostname.
+#
+# SINCE 1.7.0
+git.sshKrb5ServicePrincipalName = ""
+
+# A comma-separated list of authentication method. They will be tried in
+# the given order. Possible values are
+# "gssapi-with-mic", "publickey", "keyboard-interactive" or "password"
+#
+# SINCE 1.7.0
+git.sshAuthenticatorsOrder = "password,keyboard-interactive,publickey"
+
# SSH backend NIO2|MINA.
#
# The Apache Mina project recommends using the NIO2 backend.
@@ -762,6 +784,11 @@ web.includePersonalRepositories = false
# BASEFOLDER
web.projectsFile = ${baseFolder}/projects.conf
+# Defines the tab length for all blob views
+#
+# SINCE 1.7.0
+web.tabLength = 4
+
# Either the full path to a user config file (users.conf)
# OR a fully qualified class name that implements the IUserService interface.
#
@@ -1141,6 +1168,24 @@ web.forwardSlashCharacter = /
# SINCE 0.5.0
web.otherUrls =
+# Should HTTP/HTTPS URLs be displayed if the git servlet is enabled?
+# default: true
+#
+# SINCE 1.7.0
+web.showHttpServletUrls = true
+
+# Should git URLs be displayed if the git daemon is enabled?
+# default: true
+#
+# SINCE 1.7.0
+web.showGitDaemonUrls = true
+
+# Should SSH URLs be displayed if the SSH daemon is enabled?
+# default: true
+#
+# SINCE 1.7.0
+web.showSshDaemonUrls = true
+
# Should app-specific clone links be displayed for SourceTree, SparkleShare, etc?
#
# SINCE 1.3.0
@@ -1610,6 +1655,22 @@ federation.sets =
# SINCE 1.3.0
realm.container.autoCreateAccounts = false
+# A set of mapping used to map HTTP session attributes to user informations
+# They are used if realm.container.autoCreateAccounts is set to true and
+# the webapp container used can fill the session with user informations
+#
+# SINCE 1.7.0
+realm.container.autoAccounts.displayName =
+realm.container.autoAccounts.emailAddress =
+realm.container.autoAccounts.locale =
+
+# If the user's created by the webapp container is given this role,
+# the user created will be a admin user.
+#
+# SINCE 1.7.0
+realm.container.autoAccounts.adminRole =
+
+
# Allow or prohibit Windows guest account logins
#
# SINCE 1.3.0
diff --git a/src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java b/src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java
index 5ef03af7..e23fca78 100644
--- a/src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java
+++ b/src/main/java/com/gitblit/extensions/RepositoryLifeCycleListener.java
@@ -36,6 +36,24 @@ public abstract class RepositoryLifeCycleListener implements ExtensionPoint {
public abstract void onCreation(RepositoryModel repository);
/**
+ * Called after a repository has been forked.
+ *
+ * @param origin
+ * @param fork
+ * @since 1.7.0
+ */
+ public abstract void onFork(RepositoryModel origin, RepositoryModel fork);
+
+ /**
+ * Called after a repository has been renamed.
+ *
+ * @param oldName
+ * @param repository
+ * @since 1.7.0
+ */
+ public abstract void onRename(String oldName, RepositoryModel repository);
+
+ /**
* Called after a repository has been deleted.
*
* @param repository
diff --git a/src/main/java/com/gitblit/git/PatchsetReceivePack.java b/src/main/java/com/gitblit/git/PatchsetReceivePack.java
index 54ffb7ba..ef0b409b 100644
--- a/src/main/java/com/gitblit/git/PatchsetReceivePack.java
+++ b/src/main/java/com/gitblit/git/PatchsetReceivePack.java
@@ -667,7 +667,7 @@ public class PatchsetReceivePack extends GitblitReceivePack {
// identified the missing object earlier before we got control.
LOGGER.error("failed to get commit count", e);
} finally {
- walk.release();
+ walk.close();
}
sendError("");
@@ -1078,7 +1078,7 @@ public class PatchsetReceivePack extends GitblitReceivePack {
LOGGER.error("failed to get commit count", e);
return 0;
} finally {
- walk.release();
+ walk.close();
}
return count;
}
diff --git a/src/main/java/com/gitblit/guice/WebModule.java b/src/main/java/com/gitblit/guice/WebModule.java
index 5b569182..c6172c3d 100644
--- a/src/main/java/com/gitblit/guice/WebModule.java
+++ b/src/main/java/com/gitblit/guice/WebModule.java
@@ -19,6 +19,7 @@ import java.util.HashMap;
import java.util.Map;
import com.gitblit.Constants;
+import com.gitblit.servlet.AccessDeniedServlet;
import com.gitblit.servlet.BranchGraphServlet;
import com.gitblit.servlet.DownloadZipFilter;
import com.gitblit.servlet.DownloadZipServlet;
@@ -70,6 +71,17 @@ public class WebModule extends ServletModule {
serve("/robots.txt").with(RobotsTxtServlet.class);
serve("/logo.png").with(LogoServlet.class);
+ /* Prevent accidental access to 'resources' such as GitBlit java classes
+ *
+ * In the GO setup the JAR containing the application and the WAR injected
+ * into Jetty are the same file. However Jetty expects to serve the entire WAR
+ * contents, except the WEB-INF folder. Thus, all java binary classes in the
+ * JAR are served by default as is they were legitimate resources.
+ *
+ * The below servlet mappings prevent that behavior
+ */
+ serve(fuzzy("/com/")).with(AccessDeniedServlet.class);
+
// global filters
filter(ALL).through(ProxyFilter.class);
filter(ALL).through(EnforceAuthenticationFilter.class);
diff --git a/src/main/java/com/gitblit/manager/AuthenticationManager.java b/src/main/java/com/gitblit/manager/AuthenticationManager.java
index 29221e6f..38e45a6f 100644
--- a/src/main/java/com/gitblit/manager/AuthenticationManager.java
+++ b/src/main/java/com/gitblit/manager/AuthenticationManager.java
@@ -215,6 +215,29 @@ public class AuthenticationManager implements IAuthenticationManager {
user.displayName = username;
user.password = Constants.EXTERNAL_ACCOUNT;
user.accountType = AccountType.CONTAINER;
+
+ // Try to extract user's informations for the session
+ // it uses "realm.container.autoAccounts.*" as the attribute name to look for
+ HttpSession session = httpRequest.getSession();
+ String emailAddress = resolveAttribute(session, Keys.realm.container.autoAccounts.emailAddress);
+ if(emailAddress != null) {
+ user.emailAddress = emailAddress;
+ }
+ String displayName = resolveAttribute(session, Keys.realm.container.autoAccounts.displayName);
+ if(displayName != null) {
+ user.displayName = displayName;
+ }
+ String userLocale = resolveAttribute(session, Keys.realm.container.autoAccounts.locale);
+ if(userLocale != null) {
+ user.getPreferences().setLocale(userLocale);
+ }
+ String adminRole = settings.getString(Keys.realm.container.autoAccounts.adminRole, null);
+ if(adminRole != null && ! adminRole.isEmpty()) {
+ if(httpRequest.isUserInRole(adminRole)) {
+ user.canAdmin = true;
+ }
+ }
+
userManager.updateUserModel(user);
flagSession(httpRequest, AuthenticationType.CONTAINER);
logger.debug(MessageFormat.format("{0} authenticated and created by servlet container principal from {1}",
@@ -293,6 +316,31 @@ public class AuthenticationManager implements IAuthenticationManager {
}
return null;
}
+
+ /**
+ * Extract given attribute from the session and return it's content
+ * it return null if attributeMapping is empty, or if the value is
+ * empty
+ *
+ * @param session The user session
+ * @param attributeMapping
+ * @return
+ */
+ private String resolveAttribute(HttpSession session, String attributeMapping) {
+ String attributeName = settings.getString(attributeMapping, null);
+ if(StringUtils.isEmpty(attributeName)) {
+ return null;
+ }
+ Object attributeValue = session.getAttribute(attributeName);
+ if(attributeValue == null) {
+ return null;
+ }
+ String value = attributeValue.toString();
+ if(value.isEmpty()) {
+ return null;
+ }
+ return value;
+ }
/**
* Authenticate a user based on a public key.
@@ -326,6 +374,35 @@ public class AuthenticationManager implements IAuthenticationManager {
/**
+ * Return the UserModel for already authenticated user.
+ *
+ * This implementation assumes that the authentication has already take place
+ * (e.g. SSHDaemon) and that this is a validation/verification of the user.
+ *
+ * @param username
+ * @return a user object or null
+ */
+ @Override
+ public UserModel authenticate(String username) {
+ if (username != null) {
+ if (!StringUtils.isEmpty(username)) {
+ UserModel user = userManager.getUserModel(username);
+ if (user != null) {
+ // existing user
+ logger.debug(MessageFormat.format("{0} authenticated externally", user.username));
+ return validateAuthentication(user, AuthenticationType.CONTAINER);
+ }
+ logger.warn(MessageFormat.format("Failed to find UserModel for {0} during external authentication",
+ username));
+ }
+ } else {
+ logger.warn("Empty user passed to AuthenticationManager.authenticate!");
+ }
+ return null;
+ }
+
+
+ /**
* This method allows the authentication manager to reject authentication
* attempts. It is called after the username/secret have been verified to
* ensure that the authentication technique has been logged.
diff --git a/src/main/java/com/gitblit/manager/GitblitManager.java b/src/main/java/com/gitblit/manager/GitblitManager.java
index 9692e654..8d25b3f5 100644
--- a/src/main/java/com/gitblit/manager/GitblitManager.java
+++ b/src/main/java/com/gitblit/manager/GitblitManager.java
@@ -54,6 +54,7 @@ import com.gitblit.Constants.FederationToken;
import com.gitblit.Constants.Role;
import com.gitblit.GitBlitException;
import com.gitblit.IStoredSettings;
+import com.gitblit.extensions.RepositoryLifeCycleListener;
import com.gitblit.models.FederationModel;
import com.gitblit.models.FederationProposal;
import com.gitblit.models.FederationSet;
@@ -276,6 +277,16 @@ public class GitblitManager implements IGitblit {
// add this clone to the cached model
repositoryManager.addToCachedRepositoryList(cloneModel);
+
+ if (pluginManager != null) {
+ for (RepositoryLifeCycleListener listener : pluginManager.getExtensions(RepositoryLifeCycleListener.class)) {
+ try {
+ listener.onFork(repository, cloneModel);
+ } catch (Throwable t) {
+ logger.error(String.format("failed to call plugin onFork %s", repository.name), t);
+ }
+ }
+ }
return cloneModel;
}
@@ -651,6 +662,11 @@ public class GitblitManager implements IGitblit {
}
@Override
+ public UserModel authenticate(String username) {
+ return authenticationManager.authenticate(username);
+ }
+
+ @Override
public UserModel authenticate(HttpServletRequest httpRequest, boolean requiresCertificate) {
UserModel user = authenticationManager.authenticate(httpRequest, requiresCertificate);
if (user == null) {
diff --git a/src/main/java/com/gitblit/manager/IAuthenticationManager.java b/src/main/java/com/gitblit/manager/IAuthenticationManager.java
index d48ec534..c81092b9 100644
--- a/src/main/java/com/gitblit/manager/IAuthenticationManager.java
+++ b/src/main/java/com/gitblit/manager/IAuthenticationManager.java
@@ -71,6 +71,16 @@ public interface IAuthenticationManager extends IManager {
UserModel authenticate(String username, char[] password);
/**
+ * Return the UserModel for already authenticated user.
+ *
+ * @see IUserService.authenticate(String, char[])
+ * @param username
+ * @return a user object or null
+ * @since 1.7.0
+ */
+ UserModel authenticate(String username);
+
+ /**
* Returns the Gitlbit cookie in the request.
*
* @param request
diff --git a/src/main/java/com/gitblit/manager/RepositoryManager.java b/src/main/java/com/gitblit/manager/RepositoryManager.java
index c2c6088e..23fd0224 100644
--- a/src/main/java/com/gitblit/manager/RepositoryManager.java
+++ b/src/main/java/com/gitblit/manager/RepositoryManager.java
@@ -1375,6 +1375,7 @@ public class RepositoryManager implements IRepositoryManager {
repository.name = repository.name.substring(projectPath.length() + 1);
}
}
+ boolean isRename = false;
if (isCreate) {
// ensure created repository name ends with .git
if (!repository.name.toLowerCase().endsWith(org.eclipse.jgit.lib.Constants.DOT_GIT_EXT)) {
@@ -1391,7 +1392,8 @@ public class RepositoryManager implements IRepositoryManager {
r = JGitUtils.createRepository(repositoriesFolder, repository.name, shared);
} else {
// rename repository
- if (!repositoryName.equalsIgnoreCase(repository.name)) {
+ isRename = !repositoryName.equalsIgnoreCase(repository.name);
+ if (isRename) {
if (!repository.name.toLowerCase().endsWith(
org.eclipse.jgit.lib.Constants.DOT_GIT_EXT)) {
repository.name += org.eclipse.jgit.lib.Constants.DOT_GIT_EXT;
@@ -1511,6 +1513,14 @@ public class RepositoryManager implements IRepositoryManager {
logger.error(String.format("failed to call plugin onCreation %s", repositoryName), t);
}
}
+ } else if (isRename && pluginManager != null) {
+ for (RepositoryLifeCycleListener listener : pluginManager.getExtensions(RepositoryLifeCycleListener.class)) {
+ try {
+ listener.onRename(repositoryName, repository);
+ } catch (Throwable t) {
+ logger.error(String.format("failed to call plugin onRename %s", repositoryName), t);
+ }
+ }
}
}
diff --git a/src/main/java/com/gitblit/manager/ServicesManager.java b/src/main/java/com/gitblit/manager/ServicesManager.java
index 69e5e408..5a957a17 100644
--- a/src/main/java/com/gitblit/manager/ServicesManager.java
+++ b/src/main/java/com/gitblit/manager/ServicesManager.java
@@ -162,7 +162,8 @@ public class ServicesManager implements IServicesManager {
List<RepositoryUrl> list = new ArrayList<RepositoryUrl>();
// http/https url
- if (settings.getBoolean(Keys.git.enableGitServlet, true)) {
+ if (settings.getBoolean(Keys.git.enableGitServlet, true) &&
+ settings.getBoolean(Keys.web.showHttpServletUrls, true)) {
AccessPermission permission = user.getRepositoryPermission(repository).permission;
if (permission.exceeds(AccessPermission.NONE)) {
Transport transport = Transport.fromString(request.getScheme());
@@ -177,7 +178,8 @@ public class ServicesManager implements IServicesManager {
// ssh daemon url
String sshDaemonUrl = getSshDaemonUrl(request, user, repository);
- if (!StringUtils.isEmpty(sshDaemonUrl)) {
+ if (!StringUtils.isEmpty(sshDaemonUrl) &&
+ settings.getBoolean(Keys.web.showSshDaemonUrls, true)) {
AccessPermission permission = user.getRepositoryPermission(repository).permission;
if (permission.exceeds(AccessPermission.NONE)) {
if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(Transport.SSH)) {
@@ -192,7 +194,8 @@ public class ServicesManager implements IServicesManager {
// git daemon url
String gitDaemonUrl = getGitDaemonUrl(request, user, repository);
- if (!StringUtils.isEmpty(gitDaemonUrl)) {
+ if (!StringUtils.isEmpty(gitDaemonUrl) &&
+ settings.getBoolean(Keys.web.showGitDaemonUrls, true)) {
AccessPermission permission = getGitDaemonAccessPermission(user, repository);
if (permission.exceeds(AccessPermission.NONE)) {
if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(Transport.GIT)) {
diff --git a/src/main/java/com/gitblit/manager/UserManager.java b/src/main/java/com/gitblit/manager/UserManager.java
index 86be8bcd..0d7ee9a5 100644
--- a/src/main/java/com/gitblit/manager/UserManager.java
+++ b/src/main/java/com/gitblit/manager/UserManager.java
@@ -83,9 +83,9 @@ public class UserManager implements IUserManager {
* @param userService
*/
public void setUserService(IUserService userService) {
- logger.info(userService.toString());
this.userService = userService;
this.userService.setup(runtimeManager);
+ logger.info(userService.toString());
}
@Override
@@ -115,10 +115,12 @@ public class UserManager implements IUserManager {
// check to see if this "file" is a custom user service class
Class<?> realmClass = Class.forName(realm);
service = (IUserService) realmClass.newInstance();
- } catch (Throwable t) {
+ } catch (ClassNotFoundException t) {
// typical file path configuration
File realmFile = runtimeManager.getFileOrFolder(Keys.realm.userService, "${baseFolder}/users.conf");
service = createUserService(realmFile);
+ } catch (InstantiationException | IllegalAccessException e) {
+ logger.error("failed to instanciate user service {}: {}", realm, e.getMessage());
}
}
setUserService(service);
diff --git a/src/main/java/com/gitblit/service/LuceneService.java b/src/main/java/com/gitblit/service/LuceneService.java
index 3f7635f4..285ea8d7 100644
--- a/src/main/java/com/gitblit/service/LuceneService.java
+++ b/src/main/java/com/gitblit/service/LuceneService.java
@@ -615,7 +615,7 @@ public class LuceneService implements Runnable {
}
// finished
- reader.release();
+ reader.close();
// commit all changes and reset the searcher
config.setInt(CONF_INDEX, null, CONF_VERSION, INDEX_VERSION);
@@ -1104,6 +1104,7 @@ public class LuceneService implements Runnable {
content = "";
}
+ int tabLength = storedSettings.getInteger(Keys.web.tabLength, 4);
int fragmentLength = SearchObjectType.commit == result.type ? 512 : 150;
QueryScorer scorer = new QueryScorer(query, "content");
@@ -1126,7 +1127,7 @@ public class LuceneService implements Runnable {
if (fragment.length() > fragmentLength) {
fragment = fragment.substring(0, fragmentLength) + "...";
}
- return "<pre class=\"text\">" + StringUtils.escapeForHtml(fragment, true) + "</pre>";
+ return "<pre class=\"text\">" + StringUtils.escapeForHtml(fragment, true, tabLength) + "</pre>";
}
// make sure we have unique fragments
diff --git a/src/main/java/com/gitblit/servlet/AccessDeniedServlet.java b/src/main/java/com/gitblit/servlet/AccessDeniedServlet.java
new file mode 100644
index 00000000..ae0797e2
--- /dev/null
+++ b/src/main/java/com/gitblit/servlet/AccessDeniedServlet.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2015 Jean-Baptiste Mayer
+ *
+ * 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.servlet;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServlet;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import com.google.inject.Singleton;
+
+/**
+ * Access-denied Servlet.
+ *
+ * This servlet serves only 404 Not Found error replies.
+ *
+ * This servlet is used to override the container's default behavior to serve
+ * all contents of the application's WAR. We can selectively prevent access to
+ * a specific path simply by mapping this servlet onto specific paths.
+ *
+ *
+ * @author Jean-Baptiste Mayer
+ *
+ */
+@Singleton
+public class AccessDeniedServlet extends HttpServlet {
+ /**
+ *
+ */
+ private static final long serialVersionUID = -3239463647917811122L;
+
+ @Override
+ protected void doPost(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, java.io.IOException {
+ processRequest(request, response);
+ }
+
+ @Override
+ protected void doGet(HttpServletRequest request, HttpServletResponse response)
+ throws ServletException, IOException {
+ processRequest(request, response);
+ }
+
+ private void processRequest(HttpServletRequest request,
+ HttpServletResponse response) {
+ response.setStatus(HttpServletResponse.SC_NOT_FOUND);
+ }
+}
diff --git a/src/main/java/com/gitblit/servlet/RawServlet.java b/src/main/java/com/gitblit/servlet/RawServlet.java
index 16d1a977..1d2724bc 100644
--- a/src/main/java/com/gitblit/servlet/RawServlet.java
+++ b/src/main/java/com/gitblit/servlet/RawServlet.java
@@ -24,6 +24,7 @@ import java.text.MessageFormat;
import java.text.ParseException;
import java.util.ArrayList;
import java.util.Date;
+import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;
@@ -228,23 +229,31 @@ public class RawServlet extends HttpServlet {
return;
}
+ Map<String, String> quickContentTypes = new HashMap<>();
+ quickContentTypes.put("html", "text/html");
+ quickContentTypes.put("htm", "text/html");
+ quickContentTypes.put("xml", "application/xml");
+ quickContentTypes.put("json", "application/json");
List<PathModel> pathEntries = JGitUtils.getFilesInPath(r, requestedPath, commit);
if (pathEntries.isEmpty()) {
// requested a specific resource
String file = StringUtils.getLastPathElement(requestedPath);
try {
- String contentType;
- List<String> exts = runtimeManager.getSettings().getStrings(Keys.web.prettyPrintExtensions);
String ext = StringUtils.getFileExtension(file).toLowerCase();
- if (exts.contains(ext)) {
- // extension is a registered text type for pretty printing
- contentType = "text/plain";
- } else {
- // query Tika for the content type
- Tika tika = new Tika();
- contentType = tika.detect(file);
+ String contentType = quickContentTypes.get(ext);
+
+ if (contentType == null) {
+ List<String> exts = runtimeManager.getSettings().getStrings(Keys.web.prettyPrintExtensions);
+ if (exts.contains(ext)) {
+ // extension is a registered text type for pretty printing
+ contentType = "text/plain";
+ } else {
+ // query Tika for the content type
+ Tika tika = new Tika();
+ contentType = tika.detect(file);
+ }
}
if (contentType == null) {
@@ -459,7 +468,7 @@ public class RawServlet extends HttpServlet {
served = true;
}
} finally {
- tw.release();
+ tw.close();
rw.dispose();
}
diff --git a/src/main/java/com/gitblit/tickets/BranchTicketService.java b/src/main/java/com/gitblit/tickets/BranchTicketService.java
index 42189bfd..83966939 100644
--- a/src/main/java/com/gitblit/tickets/BranchTicketService.java
+++ b/src/main/java/com/gitblit/tickets/BranchTicketService.java
@@ -297,7 +297,7 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi
log.error("failed to read " + file, e);
} finally {
if (rw != null) {
- rw.release();
+ rw.close();
}
}
return null;
@@ -353,7 +353,7 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi
} catch (IOException e) {
log.error("", e);
} finally {
- inserter.release();
+ inserter.close();
}
}
@@ -712,7 +712,7 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi
} finally {
// release the treewalk
if (treeWalk != null) {
- treeWalk.release();
+ treeWalk.close();
}
}
} finally {
@@ -811,7 +811,7 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi
// finish the index
builder.finish();
} finally {
- inserter.release();
+ inserter.close();
}
return newIndex;
}
@@ -855,7 +855,7 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi
}
} finally {
if (tw != null) {
- tw.release();
+ tw.close();
}
}
return list;
@@ -913,10 +913,10 @@ public class BranchTicketService extends ITicketService implements RefsChangedLi
rc));
}
} finally {
- revWalk.release();
+ revWalk.close();
}
} finally {
- odi.release();
+ odi.close();
}
return success;
}
diff --git a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
index 9667154f..0ff5c284 100644
--- a/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
+++ b/src/main/java/com/gitblit/transport/ssh/SshDaemon.java
@@ -23,15 +23,25 @@ import java.net.InetSocketAddress;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Locale;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.sshd.SshServer;
+import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.io.IoServiceFactoryFactory;
import org.apache.sshd.common.io.mina.MinaServiceFactoryFactory;
import org.apache.sshd.common.io.nio2.Nio2ServiceFactoryFactory;
import org.apache.sshd.common.keyprovider.FileKeyPairProvider;
import org.apache.sshd.common.util.SecurityUtils;
import org.apache.sshd.server.auth.CachingPublicKeyAuthenticator;
+import org.apache.sshd.server.UserAuth;
+import org.apache.sshd.server.auth.UserAuthKeyboardInteractive;
+import org.apache.sshd.server.auth.UserAuthPassword;
+import org.apache.sshd.server.auth.UserAuthPublicKey;
+import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.auth.gss.UserAuthGSS;
import org.bouncycastle.openssl.PEMWriter;
import org.eclipse.jgit.internal.JGitText;
import org.slf4j.Logger;
@@ -120,7 +130,49 @@ public class SshDaemon {
} else {
addr = new InetSocketAddress(bindInterface, port);
}
-
+
+ //Will do GSS ?
+ GSSAuthenticator gssAuthenticator = null;
+ if(settings.getBoolean(Keys.git.sshWithKrb5, false)) {
+ gssAuthenticator = new SshKrbAuthenticator(gitblit);
+ String keytabString = settings.getString(Keys.git.sshKrb5Keytab,
+ "");
+ if(! keytabString.isEmpty()) {
+ gssAuthenticator.setKeytabFile(keytabString);
+ }
+ String servicePrincipalName = settings.getString(Keys.git.sshKrb5ServicePrincipalName,
+ "");
+ if(! servicePrincipalName.isEmpty()) {
+ gssAuthenticator.setServicePrincipalName(servicePrincipalName);
+ }
+ }
+
+ //Sort the authenticators for sshd
+ List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<>();
+ String sshAuthenticatorsOrderString = settings.getString(Keys.git.sshAuthenticatorsOrder,
+ "password,keyboard-interactive,publickey");
+ for(String authenticator: sshAuthenticatorsOrderString.split(",")) {
+ String authenticatorName = authenticator.trim().toLowerCase(Locale.US);
+ switch (authenticatorName) {
+ case "gssapi-with-mic":
+ if(gssAuthenticator != null) {
+ userAuthFactories.add(new UserAuthGSS.Factory());
+ }
+ break;
+ case "publickey":
+ userAuthFactories.add(new UserAuthPublicKey.Factory());
+ break;
+ case "password":
+ userAuthFactories.add(new UserAuthPassword.Factory());
+ break;
+ case "keyboard-interactive":
+ userAuthFactories.add(new UserAuthKeyboardInteractive.Factory());
+ break;
+ default:
+ log.error("Unknown ssh authenticator: '{}'", authenticatorName);
+ }
+ }
+
// Create the SSH server
sshd = SshServer.setUpDefaultServer();
sshd.setPort(addr.getPort());
@@ -128,6 +180,10 @@ public class SshDaemon {
sshd.setKeyPairProvider(hostKeyPairProvider);
sshd.setPublickeyAuthenticator(new CachingPublicKeyAuthenticator(keyAuthenticator));
sshd.setPasswordAuthenticator(new UsernamePasswordAuthenticator(gitblit));
+ if(gssAuthenticator != null) {
+ sshd.setGSSAuthenticator(gssAuthenticator);
+ }
+ sshd.setUserAuthFactories(userAuthFactories);
sshd.setSessionFactory(new SshServerSessionFactory());
sshd.setFileSystemFactory(new DisabledFilesystemFactory());
sshd.setTcpipForwardingFilter(new NonForwardingFilter());
diff --git a/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java b/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java
new file mode 100644
index 00000000..8170c934
--- /dev/null
+++ b/src/main/java/com/gitblit/transport/ssh/SshKrbAuthenticator.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2015 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.transport.ssh;
+
+import com.gitblit.manager.IAuthenticationManager;
+import com.gitblit.models.UserModel;
+import java.util.Locale;
+import org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SshKrbAuthenticator extends GSSAuthenticator {
+
+ protected final Logger log = LoggerFactory.getLogger(getClass());
+ protected final IAuthenticationManager authManager;
+
+ public SshKrbAuthenticator(IAuthenticationManager authManager) {
+ this.authManager = authManager;
+ log.info("registry {}", authManager);
+ }
+
+ public boolean validateIdentity(ServerSession session, String identity) {
+ log.info("identify with kerberos {}", identity);
+ SshDaemonClient client = (SshDaemonClient)session.getAttribute(SshDaemonClient.KEY);
+ if (client.getUser() != null) {
+ log.info("{} has already authenticated!", identity);
+ return true;
+ }
+ String username = identity.toLowerCase(Locale.US);
+ UserModel user = authManager.authenticate(username);
+ if (user != null) {
+ client.setUser(user);
+ return true;
+ }
+ log.warn("could not authenticate {} for SSH", username);
+ return false;
+ }
+}
diff --git a/src/main/java/com/gitblit/utils/CompressionUtils.java b/src/main/java/com/gitblit/utils/CompressionUtils.java
index d4bfbb34..b06edd22 100644
--- a/src/main/java/com/gitblit/utils/CompressionUtils.java
+++ b/src/main/java/com/gitblit/utils/CompressionUtils.java
@@ -132,7 +132,7 @@ public class CompressionUtils {
} catch (IOException e) {
error(e, repository, "{0} failed to zip files from commit {1}", commit.getName());
} finally {
- tw.release();
+ tw.close();
rw.dispose();
}
return success;
@@ -291,7 +291,7 @@ public class CompressionUtils {
} catch (IOException e) {
error(e, repository, "{0} failed to {1} stream files from commit {2}", algorithm, commit.getName());
} finally {
- tw.release();
+ tw.close();
rw.dispose();
}
return success;
diff --git a/src/main/java/com/gitblit/utils/DiffUtils.java b/src/main/java/com/gitblit/utils/DiffUtils.java
index 09b8f801..cdebec1b 100644
--- a/src/main/java/com/gitblit/utils/DiffUtils.java
+++ b/src/main/java/com/gitblit/utils/DiffUtils.java
@@ -229,11 +229,12 @@ public class DiffUtils {
* @param commit
* @param comparator
* @param outputType
+ * @param tabLength
* @return the diff
*/
public static DiffOutput getCommitDiff(Repository repository, RevCommit commit,
- DiffComparator comparator, DiffOutputType outputType) {
- return getDiff(repository, null, commit, null, comparator, outputType);
+ DiffComparator comparator, DiffOutputType outputType, int tabLength) {
+ return getDiff(repository, null, commit, null, comparator, outputType, tabLength);
}
/**
@@ -246,11 +247,12 @@ public class DiffUtils {
* @param handler
* to use for rendering binary diffs if {@code outputType} is {@link DiffOutputType#HTML HTML}.
* May be {@code null}, resulting in the default behavior.
+ * @param tabLength
* @return the diff
*/
public static DiffOutput getCommitDiff(Repository repository, RevCommit commit,
- DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler) {
- return getDiff(repository, null, commit, null, comparator, outputType, handler);
+ DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler, int tabLength) {
+ return getDiff(repository, null, commit, null, comparator, outputType, handler, tabLength);
}
@@ -263,11 +265,12 @@ public class DiffUtils {
* @param path
* @param comparator
* @param outputType
+ * @param tabLength
* @return the diff
*/
public static DiffOutput getDiff(Repository repository, RevCommit commit, String path,
- DiffComparator comparator, DiffOutputType outputType) {
- return getDiff(repository, null, commit, path, comparator, outputType);
+ DiffComparator comparator, DiffOutputType outputType, int tabLength) {
+ return getDiff(repository, null, commit, path, comparator, outputType, tabLength);
}
/**
@@ -282,11 +285,12 @@ public class DiffUtils {
* @param handler
* to use for rendering binary diffs if {@code outputType} is {@link DiffOutputType#HTML HTML}.
* May be {@code null}, resulting in the default behavior.
+ * @param tabLength
* @return the diff
*/
public static DiffOutput getDiff(Repository repository, RevCommit commit, String path,
- DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler) {
- return getDiff(repository, null, commit, path, comparator, outputType, handler);
+ DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler, int tabLength) {
+ return getDiff(repository, null, commit, path, comparator, outputType, handler, tabLength);
}
/**
@@ -297,11 +301,13 @@ public class DiffUtils {
* @param commit
* @param comparator
* @param outputType
+ * @param tabLength
+ *
* @return the diff
*/
public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
- DiffComparator comparator, DiffOutputType outputType) {
- return getDiff(repository, baseCommit, commit, null, comparator, outputType);
+ DiffComparator comparator, DiffOutputType outputType, int tabLength) {
+ return getDiff(repository, baseCommit, commit, null, comparator, outputType, tabLength);
}
/**
@@ -315,11 +321,12 @@ public class DiffUtils {
* @param handler
* to use for rendering binary diffs if {@code outputType} is {@link DiffOutputType#HTML HTML}.
* May be {@code null}, resulting in the default behavior.
+ * @param tabLength
* @return the diff
*/
public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
- DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler) {
- return getDiff(repository, baseCommit, commit, null, comparator, outputType, handler);
+ DiffComparator comparator, DiffOutputType outputType, BinaryDiffHandler handler, int tabLength) {
+ return getDiff(repository, baseCommit, commit, null, comparator, outputType, handler, tabLength);
}
/**
@@ -335,11 +342,12 @@ public class DiffUtils {
* or folder. if unspecified, the diff is for the entire commit.
* @param outputType
* @param diffComparator
+ * @param tabLength
* @return the diff
*/
public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit,
- String path, DiffComparator diffComparator, DiffOutputType outputType) {
- return getDiff(repository, baseCommit, commit, path, diffComparator, outputType, null);
+ String path, DiffComparator diffComparator, DiffOutputType outputType, int tabLength) {
+ return getDiff(repository, baseCommit, commit, path, diffComparator, outputType, null, tabLength);
}
/**
@@ -358,10 +366,11 @@ public class DiffUtils {
* @param handler
* to use for rendering binary diffs if {@code outputType} is {@link DiffOutputType#HTML HTML}.
* May be {@code null}, resulting in the default behavior.
+ * @param tabLength
* @return the diff
*/
public static DiffOutput getDiff(Repository repository, RevCommit baseCommit, RevCommit commit, String path,
- DiffComparator comparator, DiffOutputType outputType, final BinaryDiffHandler handler) {
+ DiffComparator comparator, DiffOutputType outputType, final BinaryDiffHandler handler, int tabLength) {
DiffStat stat = null;
String diff = null;
try {
@@ -370,7 +379,7 @@ public class DiffUtils {
DiffFormatter df;
switch (outputType) {
case HTML:
- df = new GitBlitDiffFormatter(commit.getName(), path, handler);
+ df = new GitBlitDiffFormatter(commit.getName(), path, handler, tabLength);
break;
case PLAIN:
default:
diff --git a/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java b/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java
index 8f0d223a..86b7ca2e 100644
--- a/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java
+++ b/src/main/java/com/gitblit/utils/GitBlitDiffFormatter.java
@@ -127,6 +127,8 @@ public class GitBlitDiffFormatter extends DiffFormatter {
/** If {@link #truncated}, contains all entries skipped. */
private final List<DiffEntry> skipped = new ArrayList<DiffEntry>();
+ private int tabLength;
+
/**
* A {@link ResettableByteArrayOutputStream} that intercept the "Binary files differ" message produced
* by the super implementation. Unfortunately the super implementation has far too many things private;
@@ -162,11 +164,12 @@ public class GitBlitDiffFormatter extends DiffFormatter {
}
- public GitBlitDiffFormatter(String commitId, String path, BinaryDiffHandler handler) {
+ public GitBlitDiffFormatter(String commitId, String path, BinaryDiffHandler handler, int tabLength) {
super(new DiffOutputStream());
this.os = (DiffOutputStream) getOutputStream();
this.os.setFormatter(this, handler);
this.diffStat = new DiffStat(commitId);
+ this.tabLength = tabLength;
// If we have a full commitdiff, install maxima to avoid generating a super-long diff listing that
// will only tax the browser too much.
maxDiffLinesPerFile = path != null ? -1 : getLimit(DIFF_LIMIT_PER_FILE_KEY, 500, DIFF_LIMIT_PER_FILE);
@@ -453,14 +456,14 @@ public class GitBlitDiffFormatter extends DiffFormatter {
// Highlight trailing whitespace on deleted/added lines.
Matcher matcher = trailingWhitespace.matcher(line);
if (matcher.find()) {
- StringBuilder result = new StringBuilder(StringUtils.escapeForHtml(line.substring(0, matcher.start()), CONVERT_TABS));
+ StringBuilder result = new StringBuilder(StringUtils.escapeForHtml(line.substring(0, matcher.start()), CONVERT_TABS, tabLength));
result.append("<span class='trailingws-").append(prefix == '+' ? "add" : "sub").append("'>");
result.append(StringUtils.escapeForHtml(matcher.group(1), false));
result.append("</span>");
return result.toString();
}
}
- return StringUtils.escapeForHtml(line, CONVERT_TABS);
+ return StringUtils.escapeForHtml(line, CONVERT_TABS, tabLength);
}
/**
@@ -473,7 +476,8 @@ public class GitBlitDiffFormatter extends DiffFormatter {
String[] lines = html.split("\n");
StringBuilder sb = new StringBuilder();
for (String line : lines) {
- if (line.startsWith("index")) {
+ if (line.startsWith("index") || line.startsWith("similarity")
+ || line.startsWith("rename from ") || line.startsWith("rename to ")) {
// skip index lines
} else if (line.startsWith("new file") || line.startsWith("deleted file")) {
// skip new file lines
@@ -492,7 +496,7 @@ public class GitBlitDiffFormatter extends DiffFormatter {
} else {
sb.append("<th class='diff-state diff-state-sub'></th><td class=\"diff-cell remove2\">");
}
- line = StringUtils.escapeForHtml(line.substring(1), CONVERT_TABS);
+ line = StringUtils.escapeForHtml(line.substring(1), CONVERT_TABS, tabLength);
}
sb.append(line);
if (gitLinkDiff) {
diff --git a/src/main/java/com/gitblit/utils/JGitUtils.java b/src/main/java/com/gitblit/utils/JGitUtils.java
index 69084ca1..356a796c 100644
--- a/src/main/java/com/gitblit/utils/JGitUtils.java
+++ b/src/main/java/com/gitblit/utils/JGitUtils.java
@@ -774,7 +774,7 @@ public class JGitUtils {
}
} finally {
rw.dispose();
- tw.release();
+ tw.close();
}
return content;
}
@@ -885,7 +885,7 @@ public class JGitUtils {
} catch (IOException e) {
error(e, repository, "{0} failed to get files for commit {1}", commit.getName());
} finally {
- tw.release();
+ tw.close();
}
Collections.sort(list);
return list;
@@ -942,7 +942,7 @@ public class JGitUtils {
} catch (IOException e) {
error(e, repository, "{0} failed to get files for commit {1}", commit.getName());
} finally {
- tw.release();
+ tw.close();
}
Collections.sort(list);
return list;
@@ -994,7 +994,7 @@ public class JGitUtils {
.getRawMode(0), tw.getObjectId(0).getName(), commit.getId().getName(),
ChangeType.ADD));
}
- tw.release();
+ tw.close();
} else {
RevCommit parent = rw.parseCommit(commit.getParent(0).getId());
DiffStatFormatter df = new DiffStatFormatter(commit.getName());
@@ -1049,7 +1049,7 @@ public class JGitUtils {
RevCommit start = rw.parseCommit(startRange);
RevCommit end = rw.parseCommit(endRange);
list.addAll(getFilesInRange(repository, start, end));
- rw.release();
+ rw.close();
} catch (Throwable t) {
error(t, repository, "{0} failed to determine files in range {1}..{2}!", startCommit, endCommit);
}
@@ -1147,7 +1147,7 @@ public class JGitUtils {
} catch (IOException e) {
error(e, repository, "{0} failed to get documents for commit {1}", commit.getName());
} finally {
- tw.release();
+ tw.close();
}
Collections.sort(list);
return list;
@@ -2044,7 +2044,7 @@ public class JGitUtils {
error(t, repository, "{0} can't find {1} in commit {2}", path, commit.name());
} finally {
rw.dispose();
- tw.release();
+ tw.close();
}
return commitId;
}
@@ -2218,10 +2218,10 @@ public class JGitUtils {
success = false;
}
} finally {
- revWalk.release();
+ revWalk.close();
}
} finally {
- odi.release();
+ odi.close();
}
} catch (Throwable t) {
error(t, repository, "Failed to create orphan branch {1} in repository {0}", branchName);
@@ -2412,7 +2412,7 @@ public class JGitUtils {
LOGGER.error("Failed to determine canMerge", e);
} finally {
if (revWalk != null) {
- revWalk.release();
+ revWalk.close();
}
}
return MergeStatus.NOT_MERGEABLE;
@@ -2498,14 +2498,14 @@ public class JGitUtils {
// return the merge commit id
return new MergeResult(MergeStatus.MERGED, mergeCommitId.getName());
} finally {
- odi.release();
+ odi.close();
}
}
} catch (IOException e) {
LOGGER.error("Failed to merge", e);
} finally {
if (revWalk != null) {
- revWalk.release();
+ revWalk.close();
}
}
return new MergeResult(MergeStatus.FAILED, null);
diff --git a/src/main/java/com/gitblit/utils/RefLogUtils.java b/src/main/java/com/gitblit/utils/RefLogUtils.java
index f08c99e7..355c1208 100644
--- a/src/main/java/com/gitblit/utils/RefLogUtils.java
+++ b/src/main/java/com/gitblit/utils/RefLogUtils.java
@@ -294,10 +294,10 @@ public class RefLogUtils {
rc));
}
} finally {
- revWalk.release();
+ revWalk.close();
}
} finally {
- odi.release();
+ odi.close();
}
} catch (Throwable t) {
error(t, repository, "Failed to commit reflog entry to {0}");
@@ -395,12 +395,12 @@ public class RefLogUtils {
}
// release the treewalk
- treeWalk.release();
+ treeWalk.close();
// finish temporary in-core index used for this commit
dcBuilder.finish();
} finally {
- inserter.release();
+ inserter.close();
}
return inCoreIndex;
}
diff --git a/src/main/java/com/gitblit/utils/StringUtils.java b/src/main/java/com/gitblit/utils/StringUtils.java
index 087de543..643c52c3 100644
--- a/src/main/java/com/gitblit/utils/StringUtils.java
+++ b/src/main/java/com/gitblit/utils/StringUtils.java
@@ -79,6 +79,19 @@ public class StringUtils {
* @return plain text escaped for html
*/
public static String escapeForHtml(String inStr, boolean changeSpace) {
+ return escapeForHtml(inStr, changeSpace, 4);
+ }
+
+ /**
+ * Prepare text for html presentation. Replace sensitive characters with
+ * html entities.
+ *
+ * @param inStr
+ * @param changeSpace
+ * @param tabLength
+ * @return plain text escaped for html
+ */
+ public static String escapeForHtml(String inStr, boolean changeSpace, int tabLength) {
StringBuilder retStr = new StringBuilder();
int i = 0;
while (i < inStr.length()) {
@@ -93,7 +106,9 @@ public class StringUtils {
} else if (changeSpace && inStr.charAt(i) == ' ') {
retStr.append("&nbsp;");
} else if (changeSpace && inStr.charAt(i) == '\t') {
- retStr.append(" &nbsp; &nbsp;");
+ for (int j = 0; j < tabLength; j++) {
+ retStr.append("&nbsp;");
+ }
} else {
retStr.append(inStr.charAt(i));
}
diff --git a/src/main/java/com/gitblit/utils/X509Utils.java b/src/main/java/com/gitblit/utils/X509Utils.java
index fc0b797d..a2650be4 100644
--- a/src/main/java/com/gitblit/utils/X509Utils.java
+++ b/src/main/java/com/gitblit/utils/X509Utils.java
@@ -61,6 +61,7 @@ import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import javax.crypto.Cipher;
+import javax.naming.ldap.LdapName;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.pkcs.PKCSObjectIdentifiers;
@@ -1117,17 +1118,18 @@ public class X509Utils {
}
public static X509Metadata getMetadata(X509Certificate cert) {
- // manually split DN into OID components
- // this is instead of parsing with LdapName which:
- // (1) I don't trust the order of values
- // (2) it filters out values like EMAILADDRESS
- String dn = cert.getSubjectDN().getName();
Map<String, String> oids = new HashMap<String, String>();
- for (String kvp : dn.split(",")) {
- String [] val = kvp.trim().split("=");
- String oid = val[0].toUpperCase().trim();
- String data = val[1].trim();
- oids.put(oid, data);
+ try {
+ String dn = cert.getSubjectDN().getName();
+ LdapName ldapName = new LdapName(dn);
+ for (int i = 0; i < ldapName.size(); i++) {
+ String [] val = ldapName.get(i).trim().split("=", 2);
+ String oid = val[0].toUpperCase().trim();
+ String data = val[1].trim();
+ oids.put(oid, data);
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
}
X509Metadata metadata = new X509Metadata(oids.get("CN"), "whocares");
diff --git a/src/main/java/com/gitblit/wicket/pages/BlamePage.java b/src/main/java/com/gitblit/wicket/pages/BlamePage.java
index 3c850f29..e45bbbc8 100644
--- a/src/main/java/com/gitblit/wicket/pages/BlamePage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BlamePage.java
@@ -154,6 +154,7 @@ public class BlamePage extends RepositoryPage {
add(new Label("missingBlob").setVisible(false));
+ final int tabLength = app().settings().getInteger(Keys.web.tabLength, 4);
List<AnnotatedLine> lines = DiffUtils.blame(getRepository(), blobPath, objectId);
final Map<?, String> colorMap = initializeColors(activeBlameType, lines);
ListDataProvider<AnnotatedLine> blameDp = new ListDataProvider<AnnotatedLine>(lines);
@@ -212,7 +213,7 @@ public class BlamePage extends RepositoryPage {
color = colorMap.get(entry.commitId);
break;
}
- Component data = new Label("data", StringUtils.escapeForHtml(entry.data, true)).setEscapeModelStrings(false);
+ Component data = new Label("data", StringUtils.escapeForHtml(entry.data, true, tabLength)).setEscapeModelStrings(false);
data.add(new SimpleAttributeModifier("style", "background-color: " + color + ";"));
item.add(data);
}
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java b/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java
index 187e4600..adf815e6 100644
--- a/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BlobDiffPage.java
@@ -57,7 +57,7 @@ public class BlobDiffPage extends RepositoryPage {
RevCommit parent = commit.getParentCount() == 0 ? null : commit.getParent(0);
ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
parent.getName(), commit.getName(), imageExtensions);
- diff = DiffUtils.getDiff(r, commit, blobPath, diffComparator, DiffOutputType.HTML, handler).content;
+ diff = DiffUtils.getDiff(r, commit, blobPath, diffComparator, DiffOutputType.HTML, handler, 3).content;
if (handler.getImgDiffCount() > 0) {
addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
}
@@ -68,7 +68,7 @@ public class BlobDiffPage extends RepositoryPage {
RevCommit baseCommit = JGitUtils.getCommit(r, baseObjectId);
ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
baseCommit.getName(), commit.getName(), imageExtensions);
- diff = DiffUtils.getDiff(r, baseCommit, commit, blobPath, diffComparator, DiffOutputType.HTML, handler).content;
+ diff = DiffUtils.getDiff(r, baseCommit, commit, blobPath, diffComparator, DiffOutputType.HTML, handler, 3).content;
if (handler.getImgDiffCount() > 0) {
addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
}
diff --git a/src/main/java/com/gitblit/wicket/pages/BlobPage.java b/src/main/java/com/gitblit/wicket/pages/BlobPage.java
index df30e4cc..1ef8f227 100644
--- a/src/main/java/com/gitblit/wicket/pages/BlobPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/BlobPage.java
@@ -195,7 +195,8 @@ public class BlobPage extends RepositoryPage {
} else {
sb.append("<pre class=\"plainprint\">");
}
- lines = StringUtils.escapeForHtml(source, true).split("\n");
+ final int tabLength = app().settings().getInteger(Keys.web.tabLength, 4);
+ lines = StringUtils.escapeForHtml(source, true, tabLength).split("\n");
sb.append("<table width=\"100%\"><tbody>");
diff --git a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java
index 95580ed1..3754f3ef 100644
--- a/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/CommitDiffPage.java
@@ -87,8 +87,8 @@ public class CommitDiffPage extends RepositoryPage {
final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
final ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
parents.isEmpty() ? null : parents.get(0), commit.getName(), imageExtensions);
-
- final DiffOutput diff = DiffUtils.getCommitDiff(r, commit, diffComparator, DiffOutputType.HTML, handler);
+ final int tabLength = app().settings().getInteger(Keys.web.tabLength, 4);
+ final DiffOutput diff = DiffUtils.getCommitDiff(r, commit, diffComparator, DiffOutputType.HTML, handler, tabLength);
if (handler.getImgDiffCount() > 0) {
addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
}
diff --git a/src/main/java/com/gitblit/wicket/pages/ComparePage.java b/src/main/java/com/gitblit/wicket/pages/ComparePage.java
index d1710446..7e7ac2f5 100644
--- a/src/main/java/com/gitblit/wicket/pages/ComparePage.java
+++ b/src/main/java/com/gitblit/wicket/pages/ComparePage.java
@@ -119,9 +119,9 @@ public class ComparePage extends RepositoryPage {
final List<String> imageExtensions = app().settings().getStrings(Keys.web.imageExtensions);
final ImageDiffHandler handler = new ImageDiffHandler(this, repositoryName,
fromCommit.getName(), toCommit.getName(), imageExtensions);
-
final DiffComparator diffComparator = WicketUtils.getDiffComparator(params);
- final DiffOutput diff = DiffUtils.getDiff(r, fromCommit, toCommit, diffComparator, DiffOutputType.HTML, handler);
+ final int tabLength = app().settings().getInteger(Keys.web.tabLength, 4);
+ final DiffOutput diff = DiffUtils.getDiff(r, fromCommit, toCommit, diffComparator, DiffOutputType.HTML, handler, tabLength);
if (handler.getImgDiffCount() > 0) {
addBottomScript("scripts/imgdiff.js"); // Tiny support script for image diffs
}
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html
index cf94f3ca..70869a1e 100644
--- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html
+++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.html
@@ -63,6 +63,13 @@
</ul>
</div>
+ <div class="btn-group">
+ <a class="btn dropdown-toggle" data-toggle="dropdown" href="#"> <wicket:message key="gb.repository"></wicket:message>: <span style="font-weight:bold;" wicket:id="currentRepository"></span> <span class="caret"></span></a>
+ <ul class="dropdown-menu">
+ <li wicket:id="repository"><span wicket:id="repositoryLink"></span></li>
+ </ul>
+ </div>
+
<div class="btn-group pull-right">
<div class="pagination pagination-right pagination-small">
<ul>
@@ -82,4 +89,4 @@
</wicket:extend>
</body>
-</html> \ No newline at end of file
+</html>
diff --git a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java
index 187302f5..591c7fef 100644
--- a/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/MyTicketsPage.java
@@ -17,6 +17,10 @@ package com.gitblit.wicket.pages;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
import java.util.List;
import org.apache.wicket.PageParameters;
@@ -27,6 +31,7 @@ import org.apache.wicket.markup.repeater.data.DataView;
import org.apache.wicket.markup.repeater.data.ListDataProvider;
import com.gitblit.Keys;
+import com.gitblit.models.RepositoryModel;
import com.gitblit.models.TicketModel;
import com.gitblit.models.TicketModel.Status;
import com.gitblit.models.UserModel;
@@ -52,355 +57,437 @@ import com.gitblit.wicket.panels.UserTitlePanel;
*/
public class MyTicketsPage extends RootPage {
- public MyTicketsPage() {
- this(null);
- }
-
- public MyTicketsPage(PageParameters params) {
- super(params);
- setupPage("", getString("gb.myTickets"));
-
- UserModel currentUser = GitBlitWebSession.get().getUser();
- if (currentUser == null || UserModel.ANONYMOUS.equals(currentUser)) {
- setRedirect(true);
- setResponsePage(getApplication().getHomePage());
- return;
- }
-
- final String username = currentUser.getName();
- final String[] statiiParam = (params == null) ? TicketsUI.openStatii : params.getStringArray(Lucene.status.name());
- final String assignedToParam = (params == null) ? "" : params.getString(Lucene.responsible.name(), null);
- final String milestoneParam = (params == null) ? "" : params.getString(Lucene.milestone.name(), null);
- final String queryParam = (params == null || StringUtils.isEmpty(params.getString("q", null))) ? "watchedby:" + username : params.getString("q", null);
- final String searchParam = (params == null) ? "" : params.getString("s", null);
- final String sortBy = (params == null) ? "" : Lucene.fromString(params.getString("sort", Lucene.created.name())).name();
- final boolean desc = (params == null) ? true : !"asc".equals(params.getString("direction", "desc"));
-
- // add the user title panel
- add(new UserTitlePanel("userTitlePanel", currentUser, getString("gb.myTickets")));
-
- // add search form
- add(new TicketSearchForm("ticketSearchForm", null, searchParam, getClass(), params));
-
- // standard queries
- add(new BookmarkablePageLink<Void>("changesQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.type.matches(TicketModel.Type.Proposal.name()),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
-
- add(new BookmarkablePageLink<Void>("bugsQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.type.matches(TicketModel.Type.Bug.name()),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
-
- add(new BookmarkablePageLink<Void>("enhancementsQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.type.matches(TicketModel.Type.Enhancement.name()),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
-
- add(new BookmarkablePageLink<Void>("tasksQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.type.matches(TicketModel.Type.Task.name()),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
-
- add(new BookmarkablePageLink<Void>("questionsQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.type.matches(TicketModel.Type.Question.name()),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
-
- add(new BookmarkablePageLink<Void>("maintenanceQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.type.matches(TicketModel.Type.Maintenance.name()),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
-
- add(new BookmarkablePageLink<Void>("resetQuery", MyTicketsPage.class,
- queryParameters(
- null,
- milestoneParam,
- TicketsUI.openStatii,
- null,
- null,
- true,
- 1)));
-
- add(new Label("userDivider"));
- add(new BookmarkablePageLink<Void>("createdQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.createdby.matches(username),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
-
- add(new BookmarkablePageLink<Void>("watchedQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.watchedby.matches(username),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
- add(new BookmarkablePageLink<Void>("mentionsQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.mentions.matches(username),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
- add(new BookmarkablePageLink<Void>("responsibleQuery", MyTicketsPage.class,
- queryParameters(
- Lucene.responsible.matches(username),
- milestoneParam,
- statiiParam,
- assignedToParam,
- sortBy,
- desc,
- 1)));
-
- // states
- if (ArrayUtils.isEmpty(statiiParam)) {
- add(new Label("selectedStatii", getString("gb.all")));
- } else {
- add(new Label("selectedStatii", StringUtils.flattenStrings(Arrays.asList(statiiParam), ",")));
- }
- add(new BookmarkablePageLink<Void>("openTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, TicketsUI.openStatii, assignedToParam, sortBy, desc, 1)));
- add(new BookmarkablePageLink<Void>("closedTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, TicketsUI.closedStatii, assignedToParam, sortBy, desc, 1)));
- add(new BookmarkablePageLink<Void>("allTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, null, assignedToParam, sortBy, desc, 1)));
-
- // by status
- List<Status> statii = new ArrayList<Status>(Arrays.asList(Status.values()));
- statii.remove(Status.Closed);
- ListDataProvider<Status> resolutionsDp = new ListDataProvider<Status>(statii);
- DataView<Status> statiiLinks = new DataView<Status>("statii", resolutionsDp) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void populateItem(final Item<Status> item) {
- final Status status = item.getModelObject();
- PageParameters p = queryParameters(queryParam, milestoneParam, new String [] { status.name().toLowerCase() }, assignedToParam, sortBy, desc, 1);
- String css = TicketsUI.getStatusClass(status);
- item.add(new LinkPanel("statusLink", css, status.toString(), MyTicketsPage.class, p).setRenderBodyOnly(true));
- }
- };
- add(statiiLinks);
-
- List<TicketSort> sortChoices = new ArrayList<TicketSort>();
- sortChoices.add(new TicketSort(getString("gb.sortNewest"), Lucene.created.name(), true));
- sortChoices.add(new TicketSort(getString("gb.sortOldest"), Lucene.created.name(), false));
- sortChoices.add(new TicketSort(getString("gb.sortMostRecentlyUpdated"), Lucene.updated.name(), true));
- sortChoices.add(new TicketSort(getString("gb.sortLeastRecentlyUpdated"), Lucene.updated.name(), false));
- sortChoices.add(new TicketSort(getString("gb.sortMostComments"), Lucene.comments.name(), true));
- sortChoices.add(new TicketSort(getString("gb.sortLeastComments"), Lucene.comments.name(), false));
- sortChoices.add(new TicketSort(getString("gb.sortMostPatchsetRevisions"), Lucene.patchsets.name(), true));
- sortChoices.add(new TicketSort(getString("gb.sortLeastPatchsetRevisions"), Lucene.patchsets.name(), false));
- sortChoices.add(new TicketSort(getString("gb.sortMostVotes"), Lucene.votes.name(), true));
- sortChoices.add(new TicketSort(getString("gb.sortLeastVotes"), Lucene.votes.name(), false));
- sortChoices.add(new TicketSort(getString("gb.sortHighestPriority"), Lucene.priority.name(), true));
- sortChoices.add(new TicketSort(getString("gb.sortLowestPriority"), Lucene.priority.name(), false));
- sortChoices.add(new TicketSort(getString("gb.sortHighestSeverity"), Lucene.severity.name(), true));
- sortChoices.add(new TicketSort(getString("gb.sortLowestSeverity"), Lucene.severity.name(), false));
-
- TicketSort currentSort = sortChoices.get(0);
- for (TicketSort ts : sortChoices) {
- if (ts.sortBy.equals(sortBy) && desc == ts.desc) {
- currentSort = ts;
- break;
- }
- }
- add(new Label("currentSort", currentSort.name));
-
- ListDataProvider<TicketSort> sortChoicesDp = new ListDataProvider<TicketSort>(sortChoices);
- DataView<TicketSort> sortMenu = new DataView<TicketSort>("sort", sortChoicesDp) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void populateItem(final Item<TicketSort> item) {
- final TicketSort ts = item.getModelObject();
- PageParameters params = queryParameters(queryParam, milestoneParam, statiiParam, assignedToParam, ts.sortBy, ts.desc, 1);
- item.add(new LinkPanel("sortLink", null, ts.name, MyTicketsPage.class, params).setRenderBodyOnly(true));
- }
- };
- add(sortMenu);
-
- // Build Query here
- QueryBuilder qb = new QueryBuilder(queryParam);
- if (!qb.containsField(Lucene.status.name()) && !ArrayUtils.isEmpty(statiiParam)) {
- // specify the states
- boolean not = false;
- QueryBuilder q = new QueryBuilder();
- for (String state : statiiParam) {
- if (state.charAt(0) == '!') {
- not = true;
- q.and(Lucene.status.doesNotMatch(state.substring(1)));
- } else {
- q.or(Lucene.status.matches(state));
- }
- }
- if (not) {
- qb.and(q.toString());
- } else {
- qb.and(q.toSubquery().toString());
- }
- }
-
- final String luceneQuery;
- if (qb.containsField(Lucene.createdby.name())
- || qb.containsField(Lucene.responsible.name())
- || qb.containsField(Lucene.watchedby.name())) {
- // focused "my tickets" query
- luceneQuery = qb.build();
- } else {
- // general "my tickets" query
- QueryBuilder myQuery = new QueryBuilder();
- myQuery.or(Lucene.createdby.matches(username));
- myQuery.or(Lucene.responsible.matches(username));
- myQuery.or(Lucene.watchedby.matches(username));
- myQuery.and(qb.toSubquery().toString());
- luceneQuery = myQuery.build();
- }
-
- // paging links
- int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1;
- int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25);
-
- List<QueryResult> results;
- if(StringUtils.isEmpty(searchParam)) {
- results = app().tickets().queryFor(luceneQuery, page, pageSize, sortBy, desc);
- } else {
- results = app().tickets().searchFor(null, searchParam, page, pageSize);
- }
-
- int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults;
- buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, page, pageSize, results.size(), totalResults);
-
- final boolean showSwatch = app().settings().getBoolean(Keys.web.repositoryListSwatches, true);
- add(new TicketListPanel("ticketList", results, showSwatch, true));
- }
-
- protected PageParameters queryParameters(
- String query,
- String milestone,
- String[] states,
- String assignedTo,
- String sort,
- boolean descending,
- int page) {
-
- PageParameters params = WicketUtils.newRepositoryParameter("");
- if (!StringUtils.isEmpty(query)) {
- params.add("q", query);
- }
- if (!StringUtils.isEmpty(milestone)) {
- params.add(Lucene.milestone.name(), milestone);
- }
- if (!ArrayUtils.isEmpty(states)) {
- for (String state : states) {
- params.add(Lucene.status.name(), state);
- }
- }
- if (!StringUtils.isEmpty(assignedTo)) {
- params.add(Lucene.responsible.name(), assignedTo);
- }
- if (!StringUtils.isEmpty(sort)) {
- params.add("sort", sort);
- }
- if (!descending) {
- params.add("direction", "asc");
- }
- if (page > 1) {
- params.add("pg", "" + page);
- }
- return params;
- }
-
- protected void buildPager(
- final String query,
- final String milestone,
- final String [] states,
- final String assignedTo,
- final String sort,
- final boolean desc,
- final int page,
- int pageSize,
- int count,
- int total) {
-
- boolean showNav = total > (2 * pageSize);
- boolean allowPrev = page > 1;
- boolean allowNext = (pageSize * (page - 1) + count) < total;
- add(new BookmarkablePageLink<Void>("prevLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page - 1)).setEnabled(allowPrev).setVisible(showNav));
- add(new BookmarkablePageLink<Void>("nextLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, page + 1)).setEnabled(allowNext).setVisible(showNav));
-
- if (total <= pageSize) {
- add(new Label("pageLink").setVisible(false));
- return;
- }
-
- // determine page numbers to display
- int pages = count == 0 ? 0 : ((total / pageSize) + (total % pageSize == 0 ? 0 : 1));
- // preferred number of pagelinks
- int segments = 5;
- if (pages < segments) {
- // not enough data for preferred number of page links
- segments = pages;
- }
- int minpage = Math.min(Math.max(1, page - 2), pages - (segments - 1));
- int maxpage = Math.min(pages, minpage + (segments - 1));
- List<Integer> sequence = new ArrayList<Integer>();
- for (int i = minpage; i <= maxpage; i++) {
- sequence.add(i);
- }
-
- ListDataProvider<Integer> pagesDp = new ListDataProvider<Integer>(sequence);
- DataView<Integer> pagesView = new DataView<Integer>("pageLink", pagesDp) {
- private static final long serialVersionUID = 1L;
-
- @Override
- public void populateItem(final Item<Integer> item) {
- final Integer i = item.getModelObject();
- LinkPanel link = new LinkPanel("page", null, "" + i, MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, i));
- link.setRenderBodyOnly(true);
- if (i == page) {
- WicketUtils.setCssClass(item, "active");
- }
- item.add(link);
- }
- };
- add(pagesView);
- }
+ public MyTicketsPage() {
+ this(null);
+ }
+
+ public MyTicketsPage(PageParameters params) {
+ super(params);
+ setupPage("", getString("gb.myTickets"));
+
+ UserModel currentUser = GitBlitWebSession.get().getUser();
+ if (currentUser == null || UserModel.ANONYMOUS.equals(currentUser)) {
+ setRedirect(true);
+ setResponsePage(getApplication().getHomePage());
+ return;
+ }
+
+ final String username = currentUser.getName();
+
+ final String[] statiiParam = (params == null) ? TicketsUI.openStatii : params.getStringArray(Lucene.status.name());
+ final String assignedToParam = (params == null) ? "" : params.getString(Lucene.responsible.name(), null);
+ final String milestoneParam = (params == null) ? "" : params.getString(Lucene.milestone.name(), null);
+ final String queryParam = (params == null) ? null : params.getString("q", null);
+ final String searchParam = (params == null) ? "" : params.getString("s", null);
+ final String sortBy = (params == null) ? "" : Lucene.fromString(params.getString("sort", Lucene.created.name())).name();
+ final String repositoryId = (params == null) ? "" : params.getString(Lucene.rid.name(), null);
+ final boolean desc = (params == null) ? true : !"asc".equals(params.getString("direction", "desc"));
+
+
+ // add the user title panel
+ add(new UserTitlePanel("userTitlePanel", currentUser, getString("gb.myTickets")));
+
+ // add search form
+ add(new TicketSearchForm("ticketSearchForm", null, searchParam, getClass(), params));
+
+ // standard queries
+ add(new BookmarkablePageLink<Void>("changesQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.type.matches(TicketModel.Type.Proposal.name()),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+
+ add(new BookmarkablePageLink<Void>("bugsQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.type.matches(TicketModel.Type.Bug.name()),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+
+ add(new BookmarkablePageLink<Void>("enhancementsQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.type.matches(TicketModel.Type.Enhancement.name()),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+
+ add(new BookmarkablePageLink<Void>("tasksQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.type.matches(TicketModel.Type.Task.name()),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+
+ add(new BookmarkablePageLink<Void>("questionsQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.type.matches(TicketModel.Type.Question.name()),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+
+ add(new BookmarkablePageLink<Void>("maintenanceQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.type.matches(TicketModel.Type.Maintenance.name()),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+
+ add(new BookmarkablePageLink<Void>("resetQuery", MyTicketsPage.class,
+ queryParameters(
+ null,
+ milestoneParam,
+ TicketsUI.openStatii,
+ null,
+ null,
+ true,
+ null,
+ 1)));
+
+ add(new Label("userDivider"));
+ add(new BookmarkablePageLink<Void>("createdQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.createdby.matches(username),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+
+ add(new BookmarkablePageLink<Void>("watchedQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.watchedby.matches(username),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+ add(new BookmarkablePageLink<Void>("mentionsQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.mentions.matches(username),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+ add(new BookmarkablePageLink<Void>("responsibleQuery", MyTicketsPage.class,
+ queryParameters(
+ Lucene.responsible.matches(username),
+ milestoneParam,
+ statiiParam,
+ assignedToParam,
+ sortBy,
+ desc,
+ repositoryId,
+ 1)));
+
+ // states
+ if (ArrayUtils.isEmpty(statiiParam)) {
+ add(new Label("selectedStatii", getString("gb.all")));
+ } else {
+ add(new Label("selectedStatii", StringUtils.flattenStrings(Arrays.asList(statiiParam), ",")));
+ }
+ add(new BookmarkablePageLink<Void>("openTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, TicketsUI.openStatii, assignedToParam, sortBy, desc, repositoryId, 1)));
+ add(new BookmarkablePageLink<Void>("closedTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, TicketsUI.closedStatii, assignedToParam, sortBy, desc, repositoryId, 1)));
+ add(new BookmarkablePageLink<Void>("allTickets", MyTicketsPage.class, queryParameters(queryParam, milestoneParam, null, assignedToParam, sortBy, desc, repositoryId, 1)));
+
+ // by status
+ List<Status> statii = new ArrayList<Status>(Arrays.asList(Status.values()));
+ statii.remove(Status.Closed);
+ ListDataProvider<Status> resolutionsDp = new ListDataProvider<Status>(statii);
+ DataView<Status> statiiLinks = new DataView<Status>("statii", resolutionsDp) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void populateItem(final Item<Status> item) {
+ final Status status = item.getModelObject();
+ PageParameters p = queryParameters(queryParam, milestoneParam, new String [] { status.name().toLowerCase() }, assignedToParam, sortBy, desc, repositoryId, 1);
+ String css = TicketsUI.getStatusClass(status);
+ item.add(new LinkPanel("statusLink", css, status.toString(), MyTicketsPage.class, p).setRenderBodyOnly(true));
+ }
+ };
+ add(statiiLinks);
+
+ // by sort
+ List<TicketSort> sortChoices = new ArrayList<TicketSort>();
+ sortChoices.add(new TicketSort(getString("gb.sortNewest"), Lucene.created.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortOldest"), Lucene.created.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortMostRecentlyUpdated"), Lucene.updated.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLeastRecentlyUpdated"), Lucene.updated.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortMostComments"), Lucene.comments.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLeastComments"), Lucene.comments.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortMostPatchsetRevisions"), Lucene.patchsets.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLeastPatchsetRevisions"), Lucene.patchsets.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortMostVotes"), Lucene.votes.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLeastVotes"), Lucene.votes.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortHighestPriority"), Lucene.priority.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLowestPriority"), Lucene.priority.name(), false));
+ sortChoices.add(new TicketSort(getString("gb.sortHighestSeverity"), Lucene.severity.name(), true));
+ sortChoices.add(new TicketSort(getString("gb.sortLowestSeverity"), Lucene.severity.name(), false));
+
+ TicketSort currentSort = sortChoices.get(0);
+ for (TicketSort ts : sortChoices) {
+ if (ts.sortBy.equals(sortBy) && desc == ts.desc) {
+ currentSort = ts;
+ break;
+ }
+ }
+ add(new Label("currentSort", currentSort.name));
+
+ ListDataProvider<TicketSort> sortChoicesDp = new ListDataProvider<TicketSort>(sortChoices);
+ DataView<TicketSort> sortMenu = new DataView<TicketSort>("sort", sortChoicesDp) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void populateItem(final Item<TicketSort> item) {
+ final TicketSort ts = item.getModelObject();
+ PageParameters params = queryParameters(queryParam, milestoneParam, statiiParam, assignedToParam, ts.sortBy, ts.desc, repositoryId, 1);
+ item.add(new LinkPanel("sortLink", null, ts.name, MyTicketsPage.class, params).setRenderBodyOnly(true));
+ }
+ };
+ add(sortMenu);
+
+ // by repository
+ final List<QueryResult> tickets =
+ query(initializeQueryBuilder(null, username), 1, Integer.MAX_VALUE, sortBy, desc);
+ final List<RepositoryModel> repositoryChoices = correspondingRepositories(tickets);
+ Collections.sort(repositoryChoices);
+
+ final RepositoryModel noneChoice = new RepositoryModel();
+ noneChoice.name = getString("gb.all");
+ repositoryChoices.add(0, noneChoice);
+
+ RepositoryModel currentRepository = repositoryChoices.get(0);
+ for (RepositoryModel r : repositoryChoices) {
+ if (r.getRID().equals(repositoryId)) {
+ currentRepository = r;
+ break;
+ }
+ }
+ add(new Label("currentRepository", currentRepository.toString()));
+
+ ListDataProvider<RepositoryModel> repositoryChoicesDp = new ListDataProvider<RepositoryModel>(repositoryChoices);
+ DataView<RepositoryModel> repositoryMenu = new DataView<RepositoryModel>("repository", repositoryChoicesDp) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void populateItem(final Item<RepositoryModel> item) {
+ final RepositoryModel r = item.getModelObject();
+ String rid = r == noneChoice ? null : r.getRID();
+ PageParameters params = queryParameters(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, rid, 1);
+ item.add(new LinkPanel("repositoryLink", null, r.toString(), MyTicketsPage.class, params).setRenderBodyOnly(true));
+ }
+ };
+ add(repositoryMenu);
+
+ // Update query with filter criteria
+ final QueryBuilder qb = initializeQueryBuilder(queryParam, username);
+
+ if (!qb.containsField(Lucene.status.name()) && !ArrayUtils.isEmpty(statiiParam)) {
+ // specify the states
+ boolean not = false;
+ QueryBuilder q = new QueryBuilder();
+ for (String state : statiiParam) {
+ if (state.charAt(0) == '!') {
+ not = true;
+ q.and(Lucene.status.doesNotMatch(state.substring(1)));
+ } else {
+ q.or(Lucene.status.matches(state));
+ }
+ }
+
+ if (not) {
+ qb.and(q.toString());
+ } else {
+ qb.and(q.toSubquery().toString());
+ }
+ }
+
+ if (noneChoice != currentRepository && !qb.containsField(Lucene.rid.name())) {
+ QueryBuilder q1 = new QueryBuilder();
+ q1.and(Lucene.rid.matches(repositoryId));
+ qb.and(q1.toSubquery().toString());
+ }
+
+ // paging links
+ int page = (params != null) ? Math.max(1, WicketUtils.getPage(params)) : 1;
+ int pageSize = app().settings().getInteger(Keys.tickets.perPage, 25);
+
+ final List<QueryResult> results =
+ StringUtils.isEmpty(searchParam) ? query(qb, page, pageSize, sortBy, desc) : search(searchParam, page, pageSize);
+
+ int totalResults = results.size() == 0 ? 0 : results.get(0).totalResults;
+ buildPager(queryParam, milestoneParam, statiiParam, assignedToParam, sortBy, desc, repositoryId, page, pageSize, results.size(), totalResults);
+
+ final boolean showSwatch = app().settings().getBoolean(Keys.web.repositoryListSwatches, true);
+ add(new TicketListPanel("ticketList", results, showSwatch, true));
+ }
+
+ protected PageParameters queryParameters(
+ String query,
+ String milestone,
+ String[] states,
+ String assignedTo,
+ String sort,
+ boolean descending,
+ String repositoryId,
+ int page) {
+
+ PageParameters params = WicketUtils.newRepositoryParameter("");
+ if (!StringUtils.isEmpty(query)) {
+ params.add("q", query);
+ }
+ if (!StringUtils.isEmpty(milestone)) {
+ params.add(Lucene.milestone.name(), milestone);
+ }
+ if (!ArrayUtils.isEmpty(states)) {
+ for (String state : states) {
+ params.add(Lucene.status.name(), state);
+ }
+ }
+ if (!StringUtils.isEmpty(assignedTo)) {
+ params.add(Lucene.responsible.name(), assignedTo);
+ }
+ if (!StringUtils.isEmpty(sort)) {
+ params.add("sort", sort);
+ }
+ if (!descending) {
+ params.add("direction", "asc");
+ }
+ if (!StringUtils.isEmpty(repositoryId)) {
+ params.add(Lucene.rid.name(), repositoryId);
+ }
+ if (page > 1) {
+ params.add("pg", "" + page);
+ }
+ return params;
+ }
+
+ protected void buildPager(
+ final String query,
+ final String milestone,
+ final String [] states,
+ final String assignedTo,
+ final String sort,
+ final boolean desc,
+ final String repositoryId,
+ final int page,
+ int pageSize,
+ int count,
+ int total) {
+
+ boolean showNav = total > (2 * pageSize);
+ boolean allowPrev = page > 1;
+ boolean allowNext = (pageSize * (page - 1) + count) < total;
+ add(new BookmarkablePageLink<Void>("prevLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, repositoryId, page - 1)).setEnabled(allowPrev).setVisible(showNav));
+ add(new BookmarkablePageLink<Void>("nextLink", MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, repositoryId, page + 1)).setEnabled(allowNext).setVisible(showNav));
+
+ if (total <= pageSize) {
+ add(new Label("pageLink").setVisible(false));
+ return;
+ }
+
+ // determine page numbers to display
+ int pages = count == 0 ? 0 : ((total / pageSize) + (total % pageSize == 0 ? 0 : 1));
+ // preferred number of pagelinks
+ int segments = 5;
+ if (pages < segments) {
+ // not enough data for preferred number of page links
+ segments = pages;
+ }
+ int minpage = Math.min(Math.max(1, page - 2), pages - (segments - 1));
+ int maxpage = Math.min(pages, minpage + (segments - 1));
+ List<Integer> sequence = new ArrayList<Integer>();
+ for (int i = minpage; i <= maxpage; i++) {
+ sequence.add(i);
+ }
+
+ ListDataProvider<Integer> pagesDp = new ListDataProvider<Integer>(sequence);
+ DataView<Integer> pagesView = new DataView<Integer>("pageLink", pagesDp) {
+ private static final long serialVersionUID = 1L;
+
+ @Override
+ public void populateItem(final Item<Integer> item) {
+ final Integer i = item.getModelObject();
+ LinkPanel link = new LinkPanel("page", null, "" + i, MyTicketsPage.class, queryParameters(query, milestone, states, assignedTo, sort, desc, repositoryId, i));
+ link.setRenderBodyOnly(true);
+ if (i == page) {
+ WicketUtils.setCssClass(item, "active");
+ }
+ item.add(link);
+ }
+ };
+ add(pagesView);
+ }
+
+ private QueryBuilder initializeQueryBuilder(String queryparam, String username) {
+ final QueryBuilder qb = new QueryBuilder(queryparam);
+
+ // focused "my tickets"
+ if (qb.containsField(Lucene.createdby.name())
+ || qb.containsField(Lucene.responsible.name())
+ || qb.containsField(Lucene.watchedby.name())
+ || qb.containsField(Lucene.mentions.name())) {
+
+ return qb;
+ }
+
+ // general "my tickets"
+ return qb.andSubquery()
+ .or(Lucene.createdby.matches(username))
+ .or(Lucene.responsible.matches(username))
+ .or(Lucene.watchedby.matches(username))
+ .or(Lucene.mentions.matches(username))
+ .endSubquery();
+ }
+
+ private List<QueryResult> query(QueryBuilder qb, int page, int pageSize, String sortBy, boolean descending) {
+ return app().tickets().queryFor(qb.build(), page, pageSize, sortBy, descending);
+ }
+
+ private List<QueryResult> search(String searchParam, int page, int pageSize) {
+ return app().tickets().searchFor(null, searchParam, page, pageSize);
+ }
+
+ private List<RepositoryModel> correspondingRepositories(Collection<QueryResult> tickets) {
+ final HashMap<String, RepositoryModel> result = new HashMap<>();
+ for (QueryResult ticket : tickets) {
+ RepositoryModel repository = app().repositories().getRepositoryModel(ticket.repository);
+ if (!result.containsKey(repository.getRID())) {
+ result.put(repository.getRID(), repository);
+ }
+ }
+
+ return new ArrayList<>(result.values());
+ }
}
diff --git a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java
index b6c23591..d2589e6f 100644
--- a/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/NewRepositoryPage.java
@@ -359,14 +359,14 @@ public class NewRepositoryPage extends RootSubPage {
}
}
} finally {
- revWalk.release();
+ revWalk.close();
}
} catch (UnsupportedEncodingException e) {
logger().error(null, e);
} catch (IOException e) {
logger().error(null, e);
} finally {
- odi.release();
+ odi.close();
db.close();
}
return success;
diff --git a/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java b/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java
index 8aec9e63..ceca1ec2 100644
--- a/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/ReviewProposalPage.java
@@ -76,8 +76,9 @@ public class ReviewProposalPage extends RootSubPage {
sb.append(asParam(p, proposal.name, "exclude", ""));
sb.append(asParam(p, proposal.name, "include", ""));
+ final int tabLength = app().settings().getInteger(Keys.web.tabLength, 4);
add(new Label("definition", StringUtils.breakLinesForHtml(StringUtils.escapeForHtml(sb
- .toString().trim(), true))).setEscapeModelStrings(false));
+ .toString().trim(), true, tabLength))).setEscapeModelStrings(false));
List<RepositoryModel> repositories = new ArrayList<RepositoryModel>(
proposal.repositories.values());
diff --git a/src/main/java/com/gitblit/wicket/pages/SessionPage.java b/src/main/java/com/gitblit/wicket/pages/SessionPage.java
index 0dda9495..af7f2115 100644
--- a/src/main/java/com/gitblit/wicket/pages/SessionPage.java
+++ b/src/main/java/com/gitblit/wicket/pages/SessionPage.java
@@ -96,7 +96,12 @@ public abstract class SessionPage extends WebPage {
.getAttribute(Constants.AUTHENTICATION_TYPE);
// issue 62: fix session fixation vulnerability
- session.replaceSession();
+ // but only if authentication was done in the container.
+ // It avoid double change of session, that some authentication method
+ // don't like
+ if (AuthenticationType.CONTAINER != authenticationType) {
+ session.replaceSession();
+ }
session.setUser(user);
request.getSession().setAttribute(Constants.AUTHENTICATION_TYPE, authenticationType);
diff --git a/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java
index e1706a09..5233f7c9 100644
--- a/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java
+++ b/src/main/java/com/gitblit/wicket/panels/HistoryPanel.java
@@ -116,7 +116,7 @@ public class HistoryPanel extends BasePanel {
}
} catch (Exception e) {
} finally {
- tw.release();
+ tw.close();
}
}
}
diff --git a/src/site/plugins_extensions.mkd b/src/site/plugins_extensions.mkd
index 9e0d1705..82dd30bc 100644
--- a/src/site/plugins_extensions.mkd
+++ b/src/site/plugins_extensions.mkd
@@ -338,6 +338,16 @@ public class MyRepoLifeCycleListener extends RepositoryLifeCycleListener {
}
@Override
+ public void onFork(RepositoryModel origin, RepositoryModel fork) {
+ log.info("{} forked to {}", origin, fork);
+ }
+
+ @Override
+ public void onRename(String oldName, RepositoryModel repo) {
+ log.info("{} renamed to {}", oldName, repo);
+ }
+
+ @Override
public void onDeletion(RepositoryModel repo) {
log.info("Gitblit deleted {}", repo);
}
diff --git a/src/site/setup_authentication.mkd b/src/site/setup_authentication.mkd
index 87b67497..a3bf4451 100644
--- a/src/site/setup_authentication.mkd
+++ b/src/site/setup_authentication.mkd
@@ -83,10 +83,16 @@ Windows authentication is based on the use of Waffle and JNA. It is known to wo
### PAM Authentication
-PAM authentication is based on the use of libpam4j and JNA. To use this service, your Gitblit server must be installed on a Linux/Unix/MacOSX machine and the user that Gitblit runs-as must have root permissions.
+PAM authentication is based on the use of libpam4j and JNA. To use this service, your Gitblit server must be installed on a Linux/Unix/MacOSX machine.
realm.authenticationProviders = pam
- realm.pam.serviceName = system-auth
+ realm.pam.serviceName = gitblit
+
+Then define a gitblit authentication policy in `/etc/pam.d/gitblit`
+
+ # PAM configuration for the gitblit service
+ # Standard Un*x authentication.
+ @include common-auth
### Htpasswd Authentication
diff --git a/src/test/config/test-gitblit.properties b/src/test/config/test-gitblit.properties
index 78e9ab95..398047c1 100644
--- a/src/test/config/test-gitblit.properties
+++ b/src/test/config/test-gitblit.properties
@@ -9,6 +9,8 @@ git.enableGitServlet = true
git.daemonPort = 8300
git.sshPort = 29418
git.sshKeysManager = com.gitblit.transport.ssh.MemoryKeyManager
+git.sshWithKrb5 = true
+git.sshAuthenticatorsOrder = password, publickey,gssapi-with-mic,invalid
groovy.scriptsFolder = src/main/distrib/data/groovy
groovy.preReceiveScripts = blockpush
groovy.postReceiveScripts = sendmail
diff --git a/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java b/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java
index 0cdee6cb..d6ca89c6 100644
--- a/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java
+++ b/src/test/java/com/gitblit/tests/AuthenticationManagerTest.java
@@ -15,15 +15,44 @@
*/
package com.gitblit.tests;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Enumeration;
import java.util.HashMap;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+
+import javax.servlet.AsyncContext;
+import javax.servlet.DispatcherType;
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.ServletException;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import javax.servlet.http.HttpSessionContext;
+import javax.servlet.http.HttpUpgradeHandler;
+import javax.servlet.http.Part;
import org.junit.Test;
+import com.gitblit.IUserService;
+import com.gitblit.Keys;
import com.gitblit.manager.AuthenticationManager;
import com.gitblit.manager.IAuthenticationManager;
-import com.gitblit.manager.IUserManager;
+import com.gitblit.manager.IRuntimeManager;
import com.gitblit.manager.RuntimeManager;
import com.gitblit.manager.UserManager;
+import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.tests.mock.MemorySettings;
import com.gitblit.utils.XssFilter;
@@ -35,27 +64,596 @@ import com.gitblit.utils.XssFilter.AllowXssFilter;
* @author James Moger
*
*/
+@SuppressWarnings("deprecation")
public class AuthenticationManagerTest extends GitblitUnitTest {
- IUserManager users;
+ UserManager users;
+
+ private static final class DummyHttpServletRequest implements HttpServletRequest {
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String env)
+ throws UnsupportedEncodingException {
+ }
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public long getContentLengthLong() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return null;
+ }
+
+ @Override
+ public Map<String, String[]> getParameterMap() {
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String name, Object o) {
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public Enumeration<Locale> getLocales() {
+ return null;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync() throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public AsyncContext startAsync(ServletRequest servletRequest,
+ ServletResponse servletResponse)
+ throws IllegalStateException {
+ return null;
+ }
+
+ @Override
+ public boolean isAsyncStarted() {
+ return false;
+ }
+
+ @Override
+ public boolean isAsyncSupported() {
+ return false;
+ }
+
+ @Override
+ public AsyncContext getAsyncContext() {
+ return null;
+ }
+
+ @Override
+ public DispatcherType getDispatcherType() {
+ return null;
+ }
+
+ @Override
+ public String getAuthType() {
+ return null;
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return null;
+ }
+
+ @Override
+ public long getDateHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getHeaders(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getHeaderNames() {
+ return null;
+ }
+
+ @Override
+ public int getIntHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ return null;
+ }
+
+ @Override
+ public String getPathInfo() {
+ return null;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public String getQueryString() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return null;
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ if(role != null && "admin".equals(role)) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return new Principal(){
+ @Override
+ public String getName() {
+ return "sunnyjim";
+ }
+
+ };
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ @Override
+ public String getRequestURI() {
+ return null;
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return null;
+ }
+
+ @Override
+ public String getServletPath() {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession(boolean create) {
+ return null;
+ }
+
+ final Map<String, Object> sessionAttributes = new HashMap<String, Object>();
+ @Override
+ public HttpSession getSession() {
+ return new HttpSession() {
+
+ @Override
+ public long getCreationTime() {
+ return 0;
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+
+ @Override
+ public long getLastAccessedTime() {
+ return 0;
+ }
- MemorySettings getSettings() {
- return new MemorySettings(new HashMap<String, Object>());
- }
+ @Override
+ public ServletContext getServletContext() {
+ return null;
+ }
- IAuthenticationManager newAuthenticationManager() {
- XssFilter xssFilter = new AllowXssFilter();
- RuntimeManager runtime = new RuntimeManager(getSettings(), xssFilter, GitBlitSuite.BASEFOLDER).start();
- users = new UserManager(runtime, null).start();
- AuthenticationManager auth = new AuthenticationManager(runtime, users).start();
- return auth;
- }
+ @Override
+ public void setMaxInactiveInterval(int interval) {
+ }
- @Test
- public void testAuthenticate() throws Exception {
- IAuthenticationManager auth = newAuthenticationManager();
+ @Override
+ public int getMaxInactiveInterval() {
+ return 0;
+ }
- UserModel user = new UserModel("sunnyjim");
+ @Override
+ public HttpSessionContext getSessionContext() {
+ return null;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return sessionAttributes.get(name);
+ }
+
+ @Override
+ public Object getValue(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration<String> getAttributeNames() {
+ return Collections.enumeration(sessionAttributes.keySet());
+ }
+
+ @Override
+ public String[] getValueNames() {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String name,
+ Object value) {
+ }
+
+ @Override
+ public void putValue(String name, Object value) {
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+ }
+
+ @Override
+ public void removeValue(String name) {
+ }
+
+ @Override
+ public void invalidate() {
+ }
+
+ @Override
+ public boolean isNew() {
+ return false;
+ }
+
+ };
+ }
+
+ @Override
+ public String changeSessionId() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ @Override
+ public boolean authenticate(HttpServletResponse response)
+ throws IOException, ServletException {
+ return false;
+ }
+
+ @Override
+ public void login(String username, String password)
+ throws ServletException {
+ }
+
+ @Override
+ public void logout() throws ServletException {
+ }
+
+ @Override
+ public Collection<Part> getParts() throws IOException,
+ ServletException {
+ return null;
+ }
+
+ @Override
+ public Part getPart(String name) throws IOException,
+ ServletException {
+ return null;
+ }
+
+ @Override
+ public <T extends HttpUpgradeHandler> T upgrade(
+ Class<T> handlerClass) throws IOException,
+ ServletException {
+ return null;
+ }
+
+ }
+
+ HashMap<String, Object> settings = new HashMap<String, Object>();
+
+ MemorySettings getSettings() {
+ return new MemorySettings(settings);
+ }
+
+ IAuthenticationManager newAuthenticationManager() {
+ XssFilter xssFilter = new AllowXssFilter();
+ RuntimeManager runtime = new RuntimeManager(getSettings(), xssFilter, GitBlitSuite.BASEFOLDER).start();
+ users = new UserManager(runtime, null).start();
+ final Map<String, UserModel> virtualUsers = new HashMap<String, UserModel>();
+ users.setUserService(new IUserService() {
+
+ @Override
+ public void setup(IRuntimeManager runtimeManager) {
+ }
+
+ @Override
+ public String getCookie(UserModel model) {
+ return null;
+ }
+
+ @Override
+ public UserModel getUserModel(char[] cookie) {
+ return null;
+ }
+
+ @Override
+ public UserModel getUserModel(String username) {
+ return virtualUsers.get(username);
+ }
+
+ @Override
+ public boolean updateUserModel(UserModel model) {
+ virtualUsers.put(model.username, model);
+ return true;
+ }
+
+ @Override
+ public boolean updateUserModels(Collection<UserModel> models) {
+ return false;
+ }
+
+ @Override
+ public boolean updateUserModel(String username, UserModel model) {
+ virtualUsers.put(username, model);
+ return true;
+ }
+
+ @Override
+ public boolean deleteUserModel(UserModel model) {
+ return false;
+ }
+
+ @Override
+ public boolean deleteUser(String username) {
+ return false;
+ }
+
+ @Override
+ public List<String> getAllUsernames() {
+ return null;
+ }
+
+ @Override
+ public List<UserModel> getAllUsers() {
+ return null;
+ }
+
+ @Override
+ public List<String> getAllTeamNames() {
+ return null;
+ }
+
+ @Override
+ public List<TeamModel> getAllTeams() {
+ return null;
+ }
+
+ @Override
+ public List<String> getTeamNamesForRepositoryRole(String role) {
+ return null;
+ }
+
+ @Override
+ public TeamModel getTeamModel(String teamname) {
+ return null;
+ }
+
+ @Override
+ public boolean updateTeamModel(TeamModel model) {
+ return false;
+ }
+
+ @Override
+ public boolean updateTeamModels(Collection<TeamModel> models) {
+ return false;
+ }
+
+ @Override
+ public boolean updateTeamModel(String teamname, TeamModel model) {
+ return false;
+ }
+
+ @Override
+ public boolean deleteTeamModel(TeamModel model) {
+ return false;
+ }
+
+ @Override
+ public boolean deleteTeam(String teamname) {
+ return false;
+ }
+
+ @Override
+ public List<String> getUsernamesForRepositoryRole(String role) {
+ return null;
+ }
+
+ @Override
+ public boolean renameRepositoryRole(String oldRole,
+ String newRole) {
+ return false;
+ }
+
+ @Override
+ public boolean deleteRepositoryRole(String role) {
+ return false;
+ }
+
+ });
+ AuthenticationManager auth = new AuthenticationManager(runtime, users).start();
+ return auth;
+ }
+
+ @Test
+ public void testAuthenticate() throws Exception {
+ IAuthenticationManager auth = newAuthenticationManager();
+
+ UserModel user = new UserModel("sunnyjim");
user.password = "password";
users.updateUserModel(user);
@@ -65,5 +663,48 @@ public class AuthenticationManagerTest extends GitblitUnitTest {
users.updateUserModel(user);
assertNull(auth.authenticate(user.username, user.password.toCharArray()));
users.deleteUserModel(user);
- }
+ }
+
+ @Test
+ public void testContenairAuthenticate() throws Exception {
+ settings.put(Keys.realm.container.autoCreateAccounts, "true");
+ settings.put(Keys.realm.container.autoAccounts.displayName, "displayName");
+ settings.put(Keys.realm.container.autoAccounts.emailAddress, "emailAddress");
+ settings.put(Keys.realm.container.autoAccounts.adminRole, "admin");
+ settings.put(Keys.realm.container.autoAccounts.locale, "locale");
+
+ DummyHttpServletRequest request = new DummyHttpServletRequest();
+ request.sessionAttributes.put("displayName", "Sunny Jim");
+ request.sessionAttributes.put("emailAddress", "Jim.Sunny@gitblit.com");
+ request.sessionAttributes.put("locale", "it");
+
+ IAuthenticationManager auth = newAuthenticationManager();
+
+ UserModel user = auth.authenticate(request);
+
+ assertTrue(user.canAdmin);
+ assertEquals("Sunny Jim", user.displayName);
+ assertEquals("Jim.Sunny@gitblit.com", user.emailAddress);
+ assertEquals(Locale.ITALIAN, user.getPreferences().getLocale());
+ }
+
+ @Test
+ public void testContenairAuthenticateEmpty() throws Exception {
+ settings.put(Keys.realm.container.autoCreateAccounts, "true");
+ settings.put(Keys.realm.container.autoAccounts.displayName, "displayName");
+ settings.put(Keys.realm.container.autoAccounts.emailAddress, "emailAddress");
+ settings.put(Keys.realm.container.autoAccounts.adminRole, "notAdmin");
+
+ DummyHttpServletRequest request = new DummyHttpServletRequest();
+
+ IAuthenticationManager auth = newAuthenticationManager();
+
+ UserModel user = auth.authenticate(request);
+
+ assertFalse(user.canAdmin);
+ assertEquals("sunnyjim", user.displayName);
+ assertNull(user.emailAddress);
+ assertNull(user.getPreferences().getLocale());
+ }
+
}
diff --git a/src/test/java/com/gitblit/tests/DiffUtilsTest.java b/src/test/java/com/gitblit/tests/DiffUtilsTest.java
index c73e4783..e8e839a5 100644
--- a/src/test/java/com/gitblit/tests/DiffUtilsTest.java
+++ b/src/test/java/com/gitblit/tests/DiffUtilsTest.java
@@ -41,7 +41,7 @@ public class DiffUtilsTest extends GitblitUnitTest {
Repository repository = GitBlitSuite.getHelloworldRepository();
RevCommit commit = JGitUtils.getCommit(repository,
"1d0c2933a4ae69c362f76797d42d6bd182d05176");
- String diff = DiffUtils.getCommitDiff(repository, commit, DiffComparator.SHOW_WHITESPACE, DiffOutputType.PLAIN).content;
+ String diff = DiffUtils.getCommitDiff(repository, commit, DiffComparator.SHOW_WHITESPACE, DiffOutputType.PLAIN, 3).content;
repository.close();
assertTrue(diff != null && diff.length() > 0);
String expected = "- system.out.println(\"Hello World\");\n+ System.out.println(\"Hello World\"";
@@ -55,7 +55,7 @@ public class DiffUtilsTest extends GitblitUnitTest {
"8baf6a833b5579384d9b9ceb8a16b5d0ea2ec4ca");
RevCommit commit = JGitUtils.getCommit(repository,
"1d0c2933a4ae69c362f76797d42d6bd182d05176");
- String diff = DiffUtils.getDiff(repository, baseCommit, commit, DiffComparator.SHOW_WHITESPACE, DiffOutputType.PLAIN).content;
+ String diff = DiffUtils.getDiff(repository, baseCommit, commit, DiffComparator.SHOW_WHITESPACE, DiffOutputType.PLAIN, 3).content;
repository.close();
assertTrue(diff != null && diff.length() > 0);
String expected = "- system.out.println(\"Hello World\");\n+ System.out.println(\"Hello World\"";
@@ -67,7 +67,7 @@ public class DiffUtilsTest extends GitblitUnitTest {
Repository repository = GitBlitSuite.getHelloworldRepository();
RevCommit commit = JGitUtils.getCommit(repository,
"1d0c2933a4ae69c362f76797d42d6bd182d05176");
- String diff = DiffUtils.getDiff(repository, commit, "java.java", DiffComparator.SHOW_WHITESPACE, DiffOutputType.PLAIN).content;
+ String diff = DiffUtils.getDiff(repository, commit, "java.java", DiffComparator.SHOW_WHITESPACE, DiffOutputType.PLAIN, 3).content;
repository.close();
assertTrue(diff != null && diff.length() > 0);
String expected = "- system.out.println(\"Hello World\");\n+ System.out.println(\"Hello World\"";
diff --git a/src/test/java/com/gitblit/tests/GitBlitSuite.java b/src/test/java/com/gitblit/tests/GitBlitSuite.java
index bf6834d3..79a0920d 100644
--- a/src/test/java/com/gitblit/tests/GitBlitSuite.java
+++ b/src/test/java/com/gitblit/tests/GitBlitSuite.java
@@ -65,7 +65,7 @@ import com.gitblit.utils.JGitUtils;
FanoutServiceTest.class, Issue0259Test.class, Issue0271Test.class, HtpasswdAuthenticationTest.class,
ModelUtilsTest.class, JnaUtilsTest.class, LdapSyncServiceTest.class, FileTicketServiceTest.class,
BranchTicketServiceTest.class, RedisTicketServiceTest.class, AuthenticationManagerTest.class,
- SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class })
+ SshKeysDispatcherTest.class, UITicketTest.class, PathUtilsTest.class, SshKerberosAuthenticationTest.class })
public class GitBlitSuite {
public static final File BASEFOLDER = new File("data");
diff --git a/src/test/java/com/gitblit/tests/JschConfigTestSessionFactory.java b/src/test/java/com/gitblit/tests/JschConfigTestSessionFactory.java
index 5d24b401..421f3366 100644
--- a/src/test/java/com/gitblit/tests/JschConfigTestSessionFactory.java
+++ b/src/test/java/com/gitblit/tests/JschConfigTestSessionFactory.java
@@ -21,6 +21,7 @@ public class JschConfigTestSessionFactory extends JschConfigSessionFactory {
@Override
protected void configure(OpenSshConfig.Host host, Session session) {
session.setConfig("StrictHostKeyChecking", "no");
+ session.setConfig("PreferredAuthentications", "password");
}
@Override
diff --git a/src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java b/src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java
new file mode 100644
index 00000000..1bebf61e
--- /dev/null
+++ b/src/test/java/com/gitblit/tests/SshKerberosAuthenticationTest.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2015 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 org.apache.sshd.server.auth.gss.GSSAuthenticator;
+import org.apache.sshd.server.session.ServerSession;
+import org.junit.Assert;
+import org.junit.Test;
+import org.mockito.Mockito;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.gitblit.manager.AuthenticationManager;
+import com.gitblit.manager.IRuntimeManager;
+import com.gitblit.manager.IUserManager;
+import com.gitblit.models.UserModel;
+import com.gitblit.transport.ssh.SshDaemonClient;
+import com.gitblit.transport.ssh.SshKrbAuthenticator;
+
+public class SshKerberosAuthenticationTest extends GitblitUnitTest {
+
+ private static class UserModelWrapper {
+ public UserModel um;
+ }
+
+ @Test
+ public void testUserManager() {
+ IRuntimeManager rm = Mockito.mock(IRuntimeManager.class);
+
+ //Build an UserManager that can build a UserModel
+ IUserManager im = Mockito.mock(IUserManager.class);
+ Mockito.doAnswer(new Answer<Object>() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ String user = (String) args[0];
+ return new UserModel(user);
+ }
+ }).when(im).getUserModel(Mockito.anyString());
+
+ AuthenticationManager am = new AuthenticationManager(rm, im);
+
+ GSSAuthenticator gssAuthenticator = new SshKrbAuthenticator(am);
+
+ ServerSession session = Mockito.mock(ServerSession.class);
+
+ //Build an SshDaemonClient that can set and get the UserModel
+ final UserModelWrapper umw = new UserModelWrapper();
+ SshDaemonClient client = Mockito.mock(SshDaemonClient.class);
+ Mockito.when(client.getUser()).thenReturn(umw.um);
+ Mockito.doAnswer(new Answer<Object>() {
+ public Object answer(InvocationOnMock invocation) {
+ Object[] args = invocation.getArguments();
+ UserModel um = (UserModel) args[0];
+ umw.um = um;
+ return null;
+ }
+ }).when(client).setUser(Mockito.any(UserModel.class));
+
+ Mockito.when(session.getAttribute(SshDaemonClient.KEY)).thenReturn(client);
+ Assert.assertTrue(gssAuthenticator.validateIdentity(session, "jhappy"));
+
+ }
+}
diff --git a/src/test/java/com/gitblit/tests/SshUnitTest.java b/src/test/java/com/gitblit/tests/SshUnitTest.java
index 43b51b74..3def700d 100644
--- a/src/test/java/com/gitblit/tests/SshUnitTest.java
+++ b/src/test/java/com/gitblit/tests/SshUnitTest.java
@@ -24,13 +24,18 @@ import java.net.SocketAddress;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PublicKey;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import org.apache.sshd.ClientChannel;
import org.apache.sshd.ClientSession;
import org.apache.sshd.SshClient;
import org.apache.sshd.client.ServerKeyVerifier;
+import org.apache.sshd.common.NamedFactory;
import org.apache.sshd.common.util.SecurityUtils;
+import org.apache.sshd.client.UserAuth;
+import org.apache.sshd.client.auth.UserAuthPublicKey;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
@@ -102,6 +107,9 @@ public abstract class SshUnitTest extends GitblitUnitTest {
return true;
}
});
+ List<NamedFactory<UserAuth>> userAuthFactories = new ArrayList<>();
+ userAuthFactories.add(new UserAuthPublicKey.Factory());
+ client.setUserAuthFactories(userAuthFactories);
client.start();
return client;
}
diff --git a/src/test/java/com/gitblit/tests/StringUtilsTest.java b/src/test/java/com/gitblit/tests/StringUtilsTest.java
index 0fd42aad..7176b88c 100644
--- a/src/test/java/com/gitblit/tests/StringUtilsTest.java
+++ b/src/test/java/com/gitblit/tests/StringUtilsTest.java
@@ -50,7 +50,7 @@ public class StringUtilsTest extends GitblitUnitTest {
public void testEscapeForHtml() throws Exception {
String input = "& < > \" \t";
String outputNoChange = "&amp; &lt; &gt; &quot; \t";
- String outputChange = "&amp;&nbsp;&lt;&nbsp;&gt;&nbsp;&quot;&nbsp; &nbsp; &nbsp;";
+ String outputChange = "&amp;&nbsp;&lt;&nbsp;&gt;&nbsp;&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;";
assertEquals(outputNoChange, StringUtils.escapeForHtml(input, false));
assertEquals(outputChange, StringUtils.escapeForHtml(input, true));
}