import com.gitblit.utils.StringUtils;\r
\r
/**\r
+ * The AccessRestrictionFilter is a servlet filter that preprocesses requests\r
+ * that match its url pattern definition in the web.xml file.\r
+ * \r
+ * The filter extracts the name of the repository from the url and determines if\r
+ * the requested action for the repository requires a Basic authentication\r
+ * prompt. If authentication is required and no credentials are stored in the\r
+ * "Authorization" header, then a basic authentication challenge is issued.\r
* \r
* http://en.wikipedia.org/wiki/Basic_access_authentication\r
+ * \r
+ * @author James Moger\r
+ * \r
*/\r
public abstract class AccessRestrictionFilter implements Filter {\r
\r
logger = LoggerFactory.getLogger(getClass());\r
}\r
\r
+ /**\r
+ * Extract the repository name from the url.\r
+ * \r
+ * @param url\r
+ * @return repository name\r
+ */\r
protected abstract String extractRepositoryName(String url);\r
\r
- protected abstract String getUrlRequestType(String url);\r
+ /**\r
+ * Analyze the url and returns the action of the request.\r
+ * \r
+ * @param url\r
+ * @return action of the request\r
+ */\r
+ protected abstract String getUrlRequestAction(String url);\r
\r
+ /**\r
+ * Determine if the repository requires authentication.\r
+ * \r
+ * @param repository\r
+ * @return true if authentication required\r
+ */\r
protected abstract boolean requiresAuthentication(RepositoryModel repository);\r
\r
- protected abstract boolean canAccess(RepositoryModel repository, UserModel user,\r
- String restrictedUrl);\r
+ /**\r
+ * Determine if the user can access the repository and perform the specified\r
+ * action.\r
+ * \r
+ * @param repository\r
+ * @param user\r
+ * @param action\r
+ * @return true if user may execute the action on the repository\r
+ */\r
+ protected abstract boolean canAccess(RepositoryModel repository, UserModel user, String action);\r
\r
+ /**\r
+ * doFilter does the actual work of preprocessing the request to ensure that\r
+ * the user may proceed.\r
+ * \r
+ * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)\r
+ */\r
@Override\r
public void doFilter(final ServletRequest request, final ServletResponse response,\r
final FilterChain chain) throws IOException, ServletException {\r
\r
// Determine if the request URL is restricted\r
String fullSuffix = fullUrl.substring(repository.length());\r
- String urlRequestType = getUrlRequestType(fullSuffix);\r
+ String urlRequestType = getUrlRequestAction(fullSuffix);\r
\r
// Load the repository model\r
RepositoryModel model = GitBlit.self().getRepositoryModel(repository);\r
}\r
}\r
\r
+ /**\r
+ * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)\r
+ */\r
@Override\r
public void init(final FilterConfig config) throws ServletException {\r
}\r
\r
+ /**\r
+ * @see javax.servlet.Filter#destroy()\r
+ */\r
@Override\r
public void destroy() {\r
}\r
*/\r
package com.gitblit;\r
\r
+/**\r
+ * Constant values used by Gitblit.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class Constants {\r
\r
public static final String NAME = "Gitblit";\r
import com.gitblit.utils.JGitUtils;\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * Streams out a zip file from the specified repository for any tree path at any\r
+ * revision.\r
+ * \r
+ * Unlike the GitServlet and the SyndicationServlet, this servlet is not\r
+ * protected by an AccessRestrictionFilter. It performs its own authorization\r
+ * check, but it does not perform any authentication. The assumption is that\r
+ * requests to this servlet are made via the web ui and not by direct url\r
+ * access. Unauthorized requests fail with a standard 403 (FORBIDDEN) code.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class DownloadZipServlet extends HttpServlet {\r
\r
private static final long serialVersionUID = 1L;\r
super();\r
}\r
\r
+ /**\r
+ * Returns an url to this servlet for the specified parameters.\r
+ * \r
+ * @param baseURL\r
+ * @param repository\r
+ * @param objectId\r
+ * @param path\r
+ * @return an url\r
+ */\r
public static String asLink(String baseURL, String repository, String objectId, String path) {\r
if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {\r
baseURL = baseURL.substring(0, baseURL.length() - 1);\r
+ (objectId == null ? "" : ("&h=" + objectId));\r
}\r
\r
+ /**\r
+ * Performs the authorization and zip streaming of the specified elements.\r
+ * \r
+ * @param request\r
+ * @param response\r
+ * @throws javax.servlet.ServletException\r
+ * @throws java.io.IOException\r
+ */\r
private void processRequest(javax.servlet.http.HttpServletRequest request,\r
javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,\r
java.io.IOException {\r
Date date = JGitUtils.getCommitDate(commit);\r
String contentType = "application/octet-stream";\r
response.setContentType(contentType + "; charset=" + response.getCharacterEncoding());\r
- // response.setContentLength(attachment.getFileSize());\r
response.setHeader("Content-Disposition", "attachment; filename=\"" + name + ".zip"\r
+ "\"");\r
response.setDateHeader("Last-Modified", date.getTime());\r
import java.util.Properties;\r
\r
/**\r
- * Reads GitBlit settings file.\r
+ * Dynamically loads and reloads a properties file by keeping track of the last\r
+ * modification date.\r
+ * \r
+ * @author James Moger\r
* \r
*/\r
public class FileSettings extends IStoredSettings {\r
\r
private final Properties properties = new Properties();\r
\r
- private volatile long lastread;\r
+ private volatile long lastModified;\r
\r
public FileSettings(String file) {\r
super(FileSettings.class);\r
this.propertiesFile = new File(file);\r
}\r
\r
+ /**\r
+ * Returns a properties object which contains the most recent contents of\r
+ * the properties file.\r
+ */\r
@Override\r
protected synchronized Properties read() {\r
- if (propertiesFile.exists() && (propertiesFile.lastModified() > lastread)) {\r
+ if (propertiesFile.exists() && (propertiesFile.lastModified() > lastModified)) {\r
FileInputStream is = null;\r
try {\r
Properties props = new Properties();\r
// load properties after we have successfully read file\r
properties.clear();\r
properties.putAll(props);\r
- lastread = propertiesFile.lastModified();\r
+ lastModified = propertiesFile.lastModified();\r
} catch (FileNotFoundException f) {\r
// IGNORE - won't happen because file.exists() check above\r
} catch (Throwable t) {\r
return properties;\r
}\r
\r
- protected long lastRead() {\r
- return lastread;\r
+ /**\r
+ * @return the last modification date of the properties file\r
+ */\r
+ protected long lastModified() {\r
+ return lastModified;\r
}\r
\r
@Override\r
import com.gitblit.models.UserModel;\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * FileUserService is Gitblit's default user service implementation.\r
+ * \r
+ * Users and their repository memberships are stored in a simple properties file\r
+ * which is cached and dynamically reloaded when modified.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class FileUserService extends FileSettings implements IUserService {\r
\r
private final Logger logger = LoggerFactory.getLogger(FileUserService.class);\r
super(realmFile.getAbsolutePath());\r
}\r
\r
+ /**\r
+ * Does the user service support cookie authentication?\r
+ * \r
+ * @return true or false\r
+ */\r
@Override\r
public boolean supportsCookies() {\r
return true;\r
}\r
\r
+ /**\r
+ * Returns the cookie value for the specified user.\r
+ * \r
+ * @param model\r
+ * @return cookie value\r
+ */\r
@Override\r
public char[] getCookie(UserModel model) {\r
Properties allUsers = super.read();\r
return cookie.toCharArray();\r
}\r
\r
+ /**\r
+ * Authenticate a user based on their cookie.\r
+ * \r
+ * @param cookie\r
+ * @return a user object or null\r
+ */\r
@Override\r
public UserModel authenticate(char[] cookie) {\r
String hash = new String(cookie);\r
return model;\r
}\r
\r
+ /**\r
+ * Authenticate a user based on a username and password.\r
+ * \r
+ * @param username\r
+ * @param password\r
+ * @return a user object or null\r
+ */\r
@Override\r
public UserModel authenticate(String username, char[] password) {\r
Properties allUsers = read();\r
return returnedUser;\r
}\r
\r
+ /**\r
+ * Retrieve the user object for the specified username.\r
+ * \r
+ * @param username\r
+ * @return a user object or null\r
+ */\r
@Override\r
public UserModel getUserModel(String username) {\r
Properties allUsers = read();\r
return model;\r
}\r
\r
+ /**\r
+ * Updates/writes a complete user object.\r
+ * \r
+ * @param model\r
+ * @return true if update is successful\r
+ */\r
@Override\r
public boolean updateUserModel(UserModel model) {\r
return updateUserModel(model.username, model);\r
}\r
\r
+ /**\r
+ * Updates/writes and replaces a complete user object keyed by username.\r
+ * This method allows for renaming a user.\r
+ * \r
+ * @param username\r
+ * the old username\r
+ * @param model\r
+ * the user object to use for username\r
+ * @return true if update is successful\r
+ */\r
@Override\r
public boolean updateUserModel(String username, UserModel model) {\r
try {\r
return false;\r
}\r
\r
+ /**\r
+ * Deletes the user object from the user service.\r
+ * \r
+ * @param model\r
+ * @return true if successful\r
+ */\r
@Override\r
public boolean deleteUserModel(UserModel model) {\r
return deleteUser(model.username);\r
}\r
\r
+ /**\r
+ * Delete the user object with the specified username\r
+ * \r
+ * @param username\r
+ * @return true if successful\r
+ */\r
@Override\r
public boolean deleteUser(String username) {\r
try {\r
return false;\r
}\r
\r
+ /**\r
+ * Returns the list of all users available to the login service.\r
+ * \r
+ * @return list of all usernames\r
+ */\r
@Override\r
public List<String> getAllUsernames() {\r
Properties allUsers = read();\r
return list;\r
}\r
\r
+ /**\r
+ * Returns the list of all users who are allowed to bypass the access\r
+ * restriction placed on the specified repository.\r
+ * \r
+ * @param role\r
+ * the repository name\r
+ * @return list of all usernames that can bypass the access restriction\r
+ */\r
@Override\r
- public List<String> getUsernamesForRepository(String role) {\r
+ public List<String> getUsernamesForRepositoryRole(String role) {\r
List<String> list = new ArrayList<String>();\r
try {\r
Properties allUsers = read();\r
return list;\r
}\r
\r
+ /**\r
+ * Sets the list of all uses who are allowed to bypass the access\r
+ * restriction placed on the specified repository.\r
+ * \r
+ * @param role\r
+ * the repository name\r
+ * @param usernames\r
+ * @return true if successful\r
+ */\r
@Override\r
- public boolean setUsernamesForRepository(String role, List<String> usernames) {\r
+ public boolean setUsernamesForRepositoryRole(String role, List<String> usernames) {\r
try {\r
Set<String> specifiedUsers = new HashSet<String>(usernames);\r
Set<String> needsAddRole = new HashSet<String>(specifiedUsers);\r
return false;\r
}\r
\r
+ /**\r
+ * Renames a repository role.\r
+ * \r
+ * @param oldRole\r
+ * @param newRole\r
+ * @return true if successful\r
+ */\r
@Override\r
public boolean renameRepositoryRole(String oldRole, String newRole) {\r
try {\r
return false;\r
}\r
\r
+ /**\r
+ * Removes a repository role from all users.\r
+ * \r
+ * @param role\r
+ * @return true if successful\r
+ */\r
@Override\r
public boolean deleteRepositoryRole(String role) {\r
try {\r
return false;\r
}\r
\r
+ /**\r
+ * Writes the properties file.\r
+ * \r
+ * @param properties\r
+ * @throws IOException\r
+ */\r
private void write(Properties properties) throws IOException {\r
- // Update realm file\r
+ // Write a temporary copy of the users file\r
File realmFileCopy = new File(propertiesFile.getAbsolutePath() + ".tmp");\r
FileWriter writer = new FileWriter(realmFileCopy);\r
properties\r
.store(writer,\r
"# Gitblit realm file format: username=password,\\#permission,repository1,repository2...");\r
writer.close();\r
+ // If the write is successful, delete the current file and rename\r
+ // the temporary copy to the original filename.\r
if (realmFileCopy.exists() && realmFileCopy.length() > 0) {\r
if (propertiesFile.delete()) {\r
if (!realmFileCopy.renameTo(propertiesFile)) {\r
}\r
}\r
\r
+ /**\r
+ * Reads the properties file and rebuilds the in-memory cookie lookup table.\r
+ */\r
@Override\r
protected synchronized Properties read() {\r
- long lastRead = lastRead();\r
+ long lastRead = lastModified();\r
Properties allUsers = super.read();\r
- if (lastRead != lastRead()) {\r
+ if (lastRead != lastModified()) {\r
// reload hash cache\r
cookies.clear();\r
for (String username : allUsers.stringPropertyNames()) {\r
import org.eclipse.jgit.lib.Repository;\r
import org.eclipse.jgit.lib.StoredConfig;\r
import org.eclipse.jgit.transport.resolver.FileResolver;\r
+import org.eclipse.jgit.transport.resolver.RepositoryResolver;\r
+import org.eclipse.jgit.transport.resolver.ServiceNotAuthorizedException;\r
import org.eclipse.jgit.transport.resolver.ServiceNotEnabledException;\r
import org.eclipse.jgit.util.FileUtils;\r
import org.slf4j.Logger;\r
import com.gitblit.utils.JGitUtils;\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * GitBlit is the servlet context listener singleton that acts as the core for\r
+ * the web ui and the servlets. This class is either directly instantiated by\r
+ * the GitBlitServer class (Gitblit GO) or is reflectively instantiated from the\r
+ * definition in the web.xml file (Gitblit WAR).\r
+ * \r
+ * This class is the central logic processor for Gitblit. All settings, user\r
+ * object, and repository object operations pass through this class.\r
+ * \r
+ * Repository Resolution. There are two pathways for finding repositories. One\r
+ * pathway, for web ui display and repository authentication & authorization, is\r
+ * within this class. The other pathway is through the standard GitServlet.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class GitBlit implements ServletContextListener {\r
\r
private static GitBlit gitblit;\r
\r
private final Logger logger = LoggerFactory.getLogger(GitBlit.class);\r
\r
- private FileResolver<Void> repositoryResolver;\r
+ private RepositoryResolver<Void> repositoryResolver;\r
\r
private File repositoriesFolder;\r
\r
\r
private IUserService userService;\r
\r
- private IStoredSettings storedSettings;\r
+ private IStoredSettings settings;\r
\r
public GitBlit() {\r
if (gitblit == null) {\r
- // Singleton reference when running in standard servlet container\r
+ // set the static singleton reference\r
gitblit = this;\r
}\r
}\r
\r
+ /**\r
+ * Returns the Gitblit singleton.\r
+ * \r
+ * @return gitblit singleton\r
+ */\r
public static GitBlit self() {\r
if (gitblit == null) {\r
- gitblit = new GitBlit();\r
+ new GitBlit();\r
}\r
return gitblit;\r
}\r
\r
+ /**\r
+ * Returns the boolean value for the specified key. If the key does not\r
+ * exist or the value for the key can not be interpreted as a boolean, the\r
+ * defaultValue is returned.\r
+ * \r
+ * @see IStoredSettings.getBoolean(String, boolean)\r
+ * @param key\r
+ * @param defaultValue\r
+ * @return key value or defaultValue\r
+ */\r
public static boolean getBoolean(String key, boolean defaultValue) {\r
- return self().storedSettings.getBoolean(key, defaultValue);\r
- }\r
-\r
+ return self().settings.getBoolean(key, defaultValue);\r
+ }\r
+\r
+ /**\r
+ * Returns the integer value for the specified key. If the key does not\r
+ * exist or the value for the key can not be interpreted as an integer, the\r
+ * defaultValue is returned.\r
+ * \r
+ * @see IStoredSettings.getInteger(String key, int defaultValue)\r
+ * @param key\r
+ * @param defaultValue\r
+ * @return key value or defaultValue\r
+ */\r
public static int getInteger(String key, int defaultValue) {\r
- return self().storedSettings.getInteger(key, defaultValue);\r
- }\r
-\r
+ return self().settings.getInteger(key, defaultValue);\r
+ }\r
+\r
+ /**\r
+ * Returns the string value for the specified key. If the key does not exist\r
+ * or the value for the key can not be interpreted as a string, the\r
+ * defaultValue is returned.\r
+ * \r
+ * @see IStoredSettings.getString(String key, String defaultValue)\r
+ * @param key\r
+ * @param defaultValue\r
+ * @return key value or defaultValue\r
+ */\r
public static String getString(String key, String defaultValue) {\r
- return self().storedSettings.getString(key, defaultValue);\r
+ return self().settings.getString(key, defaultValue);\r
}\r
\r
+ /**\r
+ * Returns a list of space-separated strings from the specified key.\r
+ * \r
+ * @see IStoredSettings.getStrings(String key)\r
+ * @param name\r
+ * @return list of strings\r
+ */\r
public static List<String> getStrings(String key) {\r
- return self().storedSettings.getStrings(key);\r
+ return self().settings.getStrings(key);\r
}\r
\r
+ /**\r
+ * Returns the list of keys whose name starts with the specified prefix. If\r
+ * the prefix is null or empty, all key names are returned.\r
+ * \r
+ * @see IStoredSettings.getAllKeys(String key)\r
+ * @param startingWith\r
+ * @return list of keys\r
+ */\r
+\r
public static List<String> getAllKeys(String startingWith) {\r
- return self().storedSettings.getAllKeys(startingWith);\r
+ return self().settings.getAllKeys(startingWith);\r
}\r
\r
+ /**\r
+ * Is Gitblit running in debug mode?\r
+ * \r
+ * @return true if Gitblit is running in debug mode\r
+ */\r
public static boolean isDebugMode() {\r
- return self().storedSettings.getBoolean(Keys.web.debugMode, false);\r
+ return self().settings.getBoolean(Keys.web.debugMode, false);\r
}\r
\r
+ /**\r
+ * Returns the list of non-Gitblit clone urls. This allows Gitblit to\r
+ * advertise alternative urls for Git client repository access.\r
+ * \r
+ * @param repositoryName\r
+ * @return list of non-gitblit clone urls\r
+ */\r
public List<String> getOtherCloneUrls(String repositoryName) {\r
List<String> cloneUrls = new ArrayList<String>();\r
- for (String url : storedSettings.getStrings(Keys.web.otherUrls)) {\r
+ for (String url : settings.getStrings(Keys.web.otherUrls)) {\r
cloneUrls.add(MessageFormat.format(url, repositoryName));\r
}\r
return cloneUrls;\r
}\r
\r
+ /**\r
+ * Set the user service. The user service authenticates all users and is\r
+ * responsible for managing user permissions.\r
+ * \r
+ * @param userService\r
+ */\r
public void setUserService(IUserService userService) {\r
logger.info("Setting up user service " + userService.toString());\r
this.userService = userService;\r
}\r
\r
+ /**\r
+ * Authenticate a user based on a username and password.\r
+ * \r
+ * @see IUserService.authenticate(String, char[])\r
+ * @param username\r
+ * @param password\r
+ * @return a user object or null\r
+ */\r
public UserModel authenticate(String username, char[] password) {\r
if (userService == null) {\r
return null;\r
return userService.authenticate(username, password);\r
}\r
\r
+ /**\r
+ * Authenticate a user based on their cookie.\r
+ * \r
+ * @param cookies\r
+ * @return a user object or null\r
+ */\r
public UserModel authenticate(Cookie[] cookies) {\r
if (userService == null) {\r
return null;\r
return null;\r
}\r
\r
+ /**\r
+ * Sets a cookie for the specified user.\r
+ * \r
+ * @param response\r
+ * @param user\r
+ */\r
public void setCookie(WebResponse response, UserModel user) {\r
if (userService == null) {\r
return;\r
}\r
}\r
\r
+ /**\r
+ * Returns the list of all users available to the login service.\r
+ * \r
+ * @see IUserService.getAllUsernames()\r
+ * @return list of all usernames\r
+ */\r
public List<String> getAllUsernames() {\r
List<String> names = new ArrayList<String>(userService.getAllUsernames());\r
Collections.sort(names);\r
return names;\r
}\r
\r
+ /**\r
+ * Delete the user object with the specified username\r
+ * \r
+ * @see IUserService.deleteUser(String)\r
+ * @param username\r
+ * @return true if successful\r
+ */\r
public boolean deleteUser(String username) {\r
return userService.deleteUser(username);\r
}\r
\r
+ /**\r
+ * Retrieve the user object for the specified username.\r
+ * \r
+ * @see IUserService.getUserModel(String)\r
+ * @param username\r
+ * @return a user object or null\r
+ */\r
public UserModel getUserModel(String username) {\r
UserModel user = userService.getUserModel(username);\r
return user;\r
}\r
\r
+ /**\r
+ * Returns the list of all users who are allowed to bypass the access\r
+ * restriction placed on the specified repository.\r
+ * \r
+ * @see IUserService.getUsernamesForRepositoryRole(String)\r
+ * @param repository\r
+ * @return list of all usernames that can bypass the access restriction\r
+ */\r
public List<String> getRepositoryUsers(RepositoryModel repository) {\r
- return userService.getUsernamesForRepository(repository.name);\r
- }\r
-\r
+ return userService.getUsernamesForRepositoryRole(repository.name);\r
+ }\r
+\r
+ /**\r
+ * Sets the list of all uses who are allowed to bypass the access\r
+ * restriction placed on the specified repository.\r
+ * \r
+ * @see IUserService.setUsernamesForRepositoryRole(String, List<String>)\r
+ * @param repository\r
+ * @param usernames\r
+ * @return true if successful\r
+ */\r
public boolean setRepositoryUsers(RepositoryModel repository, List<String> repositoryUsers) {\r
- return userService.setUsernamesForRepository(repository.name, repositoryUsers);\r
- }\r
-\r
- public void editUserModel(String username, UserModel user, boolean isCreate)\r
+ return userService.setUsernamesForRepositoryRole(repository.name, repositoryUsers);\r
+ }\r
+\r
+ /**\r
+ * Adds/updates a complete user object keyed by username. This method allows\r
+ * for renaming a user.\r
+ * \r
+ * @see IUserService.updateUserModel(String, UserModel)\r
+ * @param username\r
+ * @param user\r
+ * @param isCreate\r
+ * @throws GitBlitException\r
+ */\r
+ public void updateUserModel(String username, UserModel user, boolean isCreate)\r
throws GitBlitException {\r
if (!userService.updateUserModel(username, user)) {\r
throw new GitBlitException(isCreate ? "Failed to add user!" : "Failed to update user!");\r
}\r
}\r
\r
+ /**\r
+ * Returns the list of all repositories available to Gitblit. This method\r
+ * does not consider user access permissions.\r
+ * \r
+ * @return list of all repositories\r
+ */\r
public List<String> getRepositoryList() {\r
return JGitUtils.getRepositoryList(repositoriesFolder, exportAll,\r
- storedSettings.getBoolean(Keys.git.searchRepositoriesSubfolders, true));\r
+ settings.getBoolean(Keys.git.searchRepositoriesSubfolders, true));\r
}\r
\r
+ /**\r
+ * Returns the JGit repository for the specified name.\r
+ * \r
+ * @param repositoryName\r
+ * @return repository or null\r
+ */\r
public Repository getRepository(String repositoryName) {\r
Repository r = null;\r
try {\r
r = null;\r
logger.error("GitBlit.getRepository(String) failed to find "\r
+ new File(repositoriesFolder, repositoryName).getAbsolutePath());\r
+ } catch (ServiceNotAuthorizedException e) {\r
+ r = null;\r
+ logger.error("GitBlit.getRepository(String) failed to find "\r
+ + new File(repositoriesFolder, repositoryName).getAbsolutePath(), e);\r
} catch (ServiceNotEnabledException e) {\r
r = null;\r
- e.printStackTrace();\r
+ logger.error("GitBlit.getRepository(String) failed to find "\r
+ + new File(repositoriesFolder, repositoryName).getAbsolutePath(), e);\r
}\r
return r;\r
}\r
\r
+ /**\r
+ * Returns the list of repository models that are accessible to the user.\r
+ * \r
+ * @param user\r
+ * @return list of repository models accessible to user\r
+ */\r
public List<RepositoryModel> getRepositoryModels(UserModel user) {\r
List<String> list = getRepositoryList();\r
List<RepositoryModel> repositories = new ArrayList<RepositoryModel>();\r
return repositories;\r
}\r
\r
+ /**\r
+ * Returns a repository model if the repository exists and the user may\r
+ * access the repository.\r
+ * \r
+ * @param user\r
+ * @param repositoryName\r
+ * @return repository model or null\r
+ */\r
public RepositoryModel getRepositoryModel(UserModel user, String repositoryName) {\r
RepositoryModel model = getRepositoryModel(repositoryName);\r
if (model == null) {\r
}\r
}\r
\r
+ /**\r
+ * Returns the repository model for the specified repository. This method\r
+ * does not consider user access permissions.\r
+ * \r
+ * @param repositoryName\r
+ * @return repository model or null\r
+ */\r
public RepositoryModel getRepositoryModel(String repositoryName) {\r
Repository r = getRepository(repositoryName);\r
if (r == null) {\r
return model;\r
}\r
\r
+ /**\r
+ * Returns the gitblit string vlaue for the specified key. If key is not\r
+ * set, returns defaultValue.\r
+ * \r
+ * @param config\r
+ * @param field\r
+ * @param defaultValue\r
+ * @return field value or defaultValue\r
+ */\r
private String getConfig(StoredConfig config, String field, String defaultValue) {\r
String value = config.getString("gitblit", null, field);\r
if (StringUtils.isEmpty(value)) {\r
return value;\r
}\r
\r
+ /**\r
+ * Returns the gitblit boolean vlaue for the specified key. If key is not\r
+ * set, returns defaultValue.\r
+ * \r
+ * @param config\r
+ * @param field\r
+ * @param defaultValue\r
+ * @return field value or defaultValue\r
+ */\r
private boolean getConfig(StoredConfig config, String field, boolean defaultValue) {\r
return config.getBoolean("gitblit", field, defaultValue);\r
}\r
\r
- public void editRepositoryModel(String repositoryName, RepositoryModel repository,\r
+ /**\r
+ * Creates/updates the repository model keyed by reopsitoryName. Saves all\r
+ * repository settings in .git/config. This method allows for renaming\r
+ * repositories and will update user access permissions accordingly.\r
+ * \r
+ * All repositories created by this method are bare and automatically have\r
+ * .git appended to their names, which is the standard convention for bare\r
+ * repositories.\r
+ * \r
+ * @param repositoryName\r
+ * @param repository\r
+ * @param isCreate\r
+ * @throws GitBlitException\r
+ */\r
+ public void updateRepositoryModel(String repositoryName, RepositoryModel repository,\r
boolean isCreate) throws GitBlitException {\r
Repository r = null;\r
if (isCreate) {\r
r = repositoryResolver.open(null, repository.name);\r
} catch (RepositoryNotFoundException e) {\r
logger.error("Repository not found", e);\r
+ } catch (ServiceNotAuthorizedException e) {\r
+ logger.error("Service not authorized", e);\r
} catch (ServiceNotEnabledException e) {\r
logger.error("Service not enabled", e);\r
}\r
}\r
}\r
\r
+ /**\r
+ * Deletes the repository from the file system and removes the repository\r
+ * permission from all repository users.\r
+ * \r
+ * @param model\r
+ * @return true if successful\r
+ */\r
public boolean deleteRepositoryModel(RepositoryModel model) {\r
return deleteRepository(model.name);\r
}\r
\r
+ /**\r
+ * Deletes the repository from the file system and removes the repository\r
+ * permission from all repository users.\r
+ * \r
+ * @param repositoryName\r
+ * @return true if successful\r
+ */\r
public boolean deleteRepository(String repositoryName) {\r
try {\r
File folder = new File(repositoriesFolder, repositoryName);\r
if (folder.exists() && folder.isDirectory()) {\r
- FileUtils.delete(folder, FileUtils.RECURSIVE);\r
+ FileUtils.delete(folder, FileUtils.RECURSIVE | FileUtils.RETRY);\r
if (userService.deleteRepositoryRole(repositoryName)) {\r
return true;\r
}\r
return false;\r
}\r
\r
+ /**\r
+ * Returns an html version of the commit message with any global or\r
+ * repository-specific regular expression substitution applied.\r
+ * \r
+ * @param repositoryName\r
+ * @param text\r
+ * @return html version of the commit message\r
+ */\r
public String processCommitMessage(String repositoryName, String text) {\r
String html = StringUtils.breakLinesForHtml(text);\r
Map<String, String> map = new HashMap<String, String>();\r
// global regex keys\r
- if (storedSettings.getBoolean(Keys.regex.global, false)) {\r
- for (String key : storedSettings.getAllKeys(Keys.regex.global)) {\r
+ if (settings.getBoolean(Keys.regex.global, false)) {\r
+ for (String key : settings.getAllKeys(Keys.regex.global)) {\r
if (!key.equals(Keys.regex.global)) {\r
String subKey = key.substring(key.lastIndexOf('.') + 1);\r
- map.put(subKey, storedSettings.getString(key, ""));\r
+ map.put(subKey, settings.getString(key, ""));\r
}\r
}\r
}\r
\r
// repository-specific regex keys\r
- List<String> keys = storedSettings.getAllKeys(Keys.regex._ROOT + "."\r
+ List<String> keys = settings.getAllKeys(Keys.regex._ROOT + "."\r
+ repositoryName.toLowerCase());\r
for (String key : keys) {\r
String subKey = key.substring(key.lastIndexOf('.') + 1);\r
- map.put(subKey, storedSettings.getString(key, ""));\r
+ map.put(subKey, settings.getString(key, ""));\r
}\r
\r
for (Entry<String, String> entry : map.entrySet()) {\r
return html;\r
}\r
\r
+ /**\r
+ * Configure the Gitblit singleton with the specified settings source. This\r
+ * source may be file settings (Gitblit GO) or may be web.xml settings\r
+ * (Gitblit WAR).\r
+ * \r
+ * @param settings\r
+ */\r
public void configureContext(IStoredSettings settings) {\r
logger.info("Reading configuration from " + settings.toString());\r
- this.storedSettings = settings;\r
+ this.settings = settings;\r
repositoriesFolder = new File(settings.getString(Keys.git.repositoriesFolder, "git"));\r
logger.info("Git repositories folder " + repositoriesFolder.getAbsolutePath());\r
repositoryResolver = new FileResolver<Void>(repositoriesFolder, exportAll);\r
String realm = settings.getString(Keys.realm.userService, "users.properties");\r
IUserService loginService = null;\r
try {\r
- // Check to see if this "file" is a login service class\r
+ // check to see if this "file" is a login service class\r
Class<?> realmClass = Class.forName(realm);\r
if (IUserService.class.isAssignableFrom(realmClass)) {\r
loginService = (IUserService) realmClass.newInstance();\r
}\r
} catch (Throwable t) {\r
- // Not a login service class OR other issue\r
- // Use default file login service\r
+ // not a login service class or class could not be instantiated.\r
+ // try to use default file login service\r
File realmFile = new File(realm);\r
if (!realmFile.exists()) {\r
try {\r
setUserService(loginService);\r
}\r
\r
+ /**\r
+ * Configure Gitblit from the web.xml, if no configuration has already been\r
+ * specified.\r
+ * \r
+ * @see ServletContextListener.contextInitialize(ServletContextEvent)\r
+ */\r
@Override\r
public void contextInitialized(ServletContextEvent contextEvent) {\r
- if (storedSettings == null) {\r
- // for running gitblit as a traditional webapp in a servlet\r
- // container\r
+ if (settings == null) {\r
+ // Gitblit WAR is running in a servlet container\r
WebXmlSettings webxmlSettings = new WebXmlSettings(contextEvent.getServletContext());\r
configureContext(webxmlSettings);\r
}\r
}\r
\r
+ /**\r
+ * Gitblit is being shutdown either because the servlet container is\r
+ * shutting down or because the servlet container is re-deploying Gitblit.\r
+ */\r
@Override\r
public void contextDestroyed(ServletContextEvent contextEvent) {\r
logger.info("Gitblit context destroyed by servlet container.");\r
*/\r
package com.gitblit;\r
\r
+/**\r
+ * GitBlitException is a marginally useful class. :)\r
+ * \r
+ * @author James Moger\r
+ *\r
+ */\r
public class GitBlitException extends Exception {\r
\r
private static final long serialVersionUID = 1L;\r
import org.eclipse.jetty.server.ssl.SslSocketConnector;\r
import org.eclipse.jetty.util.thread.QueuedThreadPool;\r
import org.eclipse.jetty.webapp.WebAppContext;\r
+import org.eclipse.jgit.util.FileUtils;\r
import org.slf4j.Logger;\r
import org.slf4j.LoggerFactory;\r
\r
import com.beust.jcommander.Parameters;\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * GitBlitServer is the embedded Jetty server for Gitblit GO. This class starts\r
+ * and stops an instance of Jetty that is configured from a combination of the\r
+ * gitblit.properties file and command line parameters. JCommander is used to\r
+ * simplify command line parameter processing. This class also automatically\r
+ * generates a self-signed certificate for localhost, if the keystore does not\r
+ * already exist.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class GitBlitServer {\r
\r
private static Logger logger;\r
}\r
}\r
\r
+ /**\r
+ * Display the command line usage of Gitblit GO.\r
+ * \r
+ * @param jc\r
+ * @param t\r
+ */\r
private static void usage(JCommander jc, ParameterException t) {\r
System.out.println(Constants.BORDER);\r
System.out.println(Constants.getGitBlitVersion());\r
if (jc != null) {\r
jc.usage();\r
System.out\r
- .println("\nExample:\n java -server -Xmx1024M -jar gitblit.jar --repos c:\\git --port 80 --securePort 443");\r
+ .println("\nExample:\n java -server -Xmx1024M -jar gitblit.jar --repositoriesFolder c:\\git --httpPort 80 --httpsPort 443");\r
}\r
System.exit(0);\r
}\r
\r
/**\r
- * Stop Server.\r
+ * Stop Gitblt GO.\r
*/\r
public static void stop(Params params) {\r
try {\r
}\r
\r
/**\r
- * Start Server.\r
+ * Start Gitblit GO.\r
*/\r
private static void start(Params params) {\r
FileSettings settings = Params.FILESETTINGS;\r
String osversion = System.getProperty("os.version");\r
logger.info("Running on " + osname + " (" + osversion + ")");\r
\r
- // Determine port connectors\r
List<Connector> connectors = new ArrayList<Connector>();\r
+\r
+ // conditionally configure the http connector\r
if (params.port > 0) {\r
Connector httpConnector = createConnector(params.useNIO, params.port);\r
String bindInterface = settings.getString(Keys.server.httpBindInterface, null);\r
connectors.add(httpConnector);\r
}\r
\r
+ // conditionally configure the https connector\r
if (params.securePort > 0) {\r
File keystore = new File("keystore");\r
if (!keystore.exists()) {\r
- logger.info("Generating self-signed SSL certificate");\r
+ logger.info("Generating self-signed SSL certificate for localhost");\r
MakeCertificate.generateSelfSignedCertificate("localhost", keystore,\r
params.storePassword);\r
}\r
}\r
}\r
\r
- // tempDir = Directory where...\r
- // * WebApp is expanded\r
- //\r
+ // tempDir is where the embedded Gitblit web application is expanded and\r
+ // where Jetty creates any necessary temporary files\r
File tempDir = new File(params.temp);\r
if (tempDir.exists()) {\r
- if (!deleteRecursively(tempDir)) {\r
- logger.warn("Failed to delete temp dir " + tempDir.getAbsolutePath());\r
+ try {\r
+ FileUtils.delete(tempDir, FileUtils.RECURSIVE | FileUtils.RETRY);\r
+ } catch (IOException x) {\r
+ logger.warn("Failed to delete temp dir " + tempDir.getAbsolutePath(), x);\r
}\r
}\r
if (!tempDir.mkdirs()) {\r
return;\r
}\r
\r
- // Override settings\r
+ // Override settings from the command-line\r
settings.overrideSetting(Keys.realm.userService, params.userService);\r
settings.overrideSetting(Keys.git.repositoriesFolder, params.repositoriesFolder);\r
\r
gitblit.configureContext(settings);\r
rootContext.addEventListener(gitblit);\r
\r
- // Start the Server\r
try {\r
+ // start the shutdown monitor\r
if (params.shutdownPort > 0) {\r
Thread shutdownMonitor = new ShutdownMonitorThread(server, params);\r
shutdownMonitor.start();\r
}\r
+\r
+ // start Jetty\r
server.start();\r
server.join();\r
} catch (Exception e) {\r
}\r
}\r
\r
+ /**\r
+ * Creates an http connector.\r
+ * \r
+ * @param useNIO\r
+ * @param port\r
+ * @return an http cnonector\r
+ */\r
private static Connector createConnector(boolean useNIO, int port) {\r
Connector connector;\r
if (useNIO) {\r
return connector;\r
}\r
\r
+ /**\r
+ * Creates an https connector.\r
+ * \r
+ * @param keystore\r
+ * @param password\r
+ * @param useNIO\r
+ * @param port\r
+ * @return an https connector\r
+ */\r
private static Connector createSSLConnector(File keystore, String password, boolean useNIO,\r
int port) {\r
SslConnector connector;\r
}\r
\r
/**\r
- * Recursively delete a folder and its contents.\r
+ * The ShutdownMonitorThread opens a socket on a specified port and waits\r
+ * for an incoming connection. When that connection is accepted a shutdown\r
+ * message is issued to the running Jetty server.\r
+ * \r
+ * @author James Moger\r
* \r
- * @param folder\r
*/\r
- private static boolean deleteRecursively(File folder) {\r
- boolean deleted = true;\r
- for (File file : folder.listFiles()) {\r
- if (file.isDirectory()) {\r
- deleted &= deleteRecursively(file);\r
- } else {\r
- deleted &= file.delete();\r
- }\r
- }\r
- return deleted && folder.delete();\r
- }\r
-\r
private static class ShutdownMonitorThread extends Thread {\r
\r
private final ServerSocket socket;\r
* Authentication Parameters\r
*/\r
@Parameter(names = { "--userService" }, description = "Authentication and Authorization Service (filename or fully qualified classname)")\r
- public String userService = FILESETTINGS.getString(Keys.realm.userService, "users.properties");\r
+ public String userService = FILESETTINGS.getString(Keys.realm.userService,\r
+ "users.properties");\r
\r
/*\r
* JETTY Parameters\r
import com.gitblit.models.UserModel;\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * The GitFilter is an AccessRestrictionFilter which ensures that Git client\r
+ * requests for push, clone, or view restricted repositories are authenticated\r
+ * and authorized.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class GitFilter extends AccessRestrictionFilter {\r
\r
protected final String gitReceivePack = "/git-receive-pack";\r
protected final String[] suffixes = { gitReceivePack, gitUploadPack, "/info/refs", "/HEAD",\r
"/objects" };\r
\r
+ /**\r
+ * Extract the repository name from the url.\r
+ * \r
+ * @param url\r
+ * @return repository name\r
+ */\r
@Override\r
protected String extractRepositoryName(String url) {\r
String repository = url;\r
+ // get the repository name from the url by finding a known url suffix\r
for (String urlSuffix : suffixes) {\r
if (repository.indexOf(urlSuffix) > -1) {\r
repository = repository.substring(0, repository.indexOf(urlSuffix));\r
return repository;\r
}\r
\r
+ /**\r
+ * Analyze the url and returns the action of the request. Return values are\r
+ * either "/git-receive-pack" or "/git-upload-pack".\r
+ * \r
+ * @param url\r
+ * @return action of the request\r
+ */\r
@Override\r
- protected String getUrlRequestType(String suffix) {\r
+ protected String getUrlRequestAction(String suffix) {\r
if (!StringUtils.isEmpty(suffix)) {\r
if (suffix.startsWith(gitReceivePack)) {\r
return gitReceivePack;\r
return null;\r
}\r
\r
+ /**\r
+ * Determine if the repository requires authentication.\r
+ * \r
+ * @param repository\r
+ * @return true if authentication required\r
+ */\r
@Override\r
protected boolean requiresAuthentication(RepositoryModel repository) {\r
return repository.accessRestriction.atLeast(AccessRestrictionType.PUSH);\r
}\r
\r
+ /**\r
+ * Determine if the user can access the repository and perform the specified\r
+ * action.\r
+ * \r
+ * @param repository\r
+ * @param user\r
+ * @param action\r
+ * @return true if user may execute the action on the repository\r
+ */\r
@Override\r
- protected boolean canAccess(RepositoryModel repository, UserModel user, String urlRequestType) {\r
+ protected boolean canAccess(RepositoryModel repository, UserModel user, String action) {\r
if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {\r
// Git Servlet disabled\r
return false;\r
}\r
if (repository.isFrozen || repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) {\r
boolean authorizedUser = user.canAccessRepository(repository.name);\r
- if (urlRequestType.equals(gitReceivePack)) {\r
+ if (action.equals(gitReceivePack)) {\r
// Push request\r
if (!repository.isFrozen && authorizedUser) {\r
// clone-restricted or push-authorized\r
user.username, repository));\r
return false;\r
}\r
- } else if (urlRequestType.equals(gitUploadPack)) {\r
+ } else if (action.equals(gitUploadPack)) {\r
// Clone request\r
boolean cloneRestricted = repository.accessRestriction\r
.atLeast(AccessRestrictionType.CLONE);\r
+/*\r
+ * Copyright 2011 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
package com.gitblit;\r
\r
+/**\r
+ * The GitServlet exists to force configuration of the JGit GitServlet based on\r
+ * the Gitblit settings from either gitblit.properties or from context\r
+ * parameters in the web.xml file.\r
+ * \r
+ * Access to this servlet is protected by the GitFilter.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class GitServlet extends org.eclipse.jgit.http.server.GitServlet {\r
\r
private static final long serialVersionUID = 1L;\r
\r
+ /**\r
+ * Configure the servlet from Gitblit's configuration.\r
+ */\r
@Override\r
public String getInitParameter(String name) {\r
if (name.equals("base-path")) {\r
\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * Base class for stored settings implementations.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public abstract class IStoredSettings {\r
\r
protected final Logger logger;\r
return props;\r
}\r
\r
+ /**\r
+ * Returns the list of keys whose name starts with the specified prefix. If\r
+ * the prefix is null or empty, all key names are returned.\r
+ * \r
+ * @param startingWith\r
+ * @return list of keys\r
+ */\r
public List<String> getAllKeys(String startingWith) {\r
List<String> keys = new ArrayList<String>();\r
Properties props = getSettings();\r
return keys;\r
}\r
\r
+ /**\r
+ * Returns the boolean value for the specified key. If the key does not\r
+ * exist or the value for the key can not be interpreted as a boolean, the\r
+ * defaultValue is returned.\r
+ * \r
+ * @param key\r
+ * @param defaultValue\r
+ * @return key value or defaultValue\r
+ */\r
public boolean getBoolean(String name, boolean defaultValue) {\r
Properties props = getSettings();\r
if (props.containsKey(name)) {\r
return defaultValue;\r
}\r
\r
+ /**\r
+ * Returns the integer value for the specified key. If the key does not\r
+ * exist or the value for the key can not be interpreted as an integer, the\r
+ * defaultValue is returned.\r
+ * \r
+ * @param key\r
+ * @param defaultValue\r
+ * @return key value or defaultValue\r
+ */\r
public int getInteger(String name, int defaultValue) {\r
Properties props = getSettings();\r
if (props.containsKey(name)) {\r
return defaultValue;\r
}\r
\r
+ /**\r
+ * Returns the string value for the specified key. If the key does not exist\r
+ * or the value for the key can not be interpreted as a string, the\r
+ * defaultValue is returned.\r
+ * \r
+ * @param key\r
+ * @param defaultValue\r
+ * @return key value or defaultValue\r
+ */\r
public String getString(String name, String defaultValue) {\r
Properties props = getSettings();\r
if (props.containsKey(name)) {\r
return defaultValue;\r
}\r
\r
+ /**\r
+ * Returns a list of space-separated strings from the specified key.\r
+ * \r
+ * @param name\r
+ * @return list of strings\r
+ */\r
public List<String> getStrings(String name) {\r
return getStrings(name, " ");\r
}\r
\r
+ /**\r
+ * Returns a list of strings from the specified key using the specified\r
+ * string separator.\r
+ * \r
+ * @param name\r
+ * @param separator\r
+ * @return list of strings\r
+ */\r
public List<String> getStrings(String name, String separator) {\r
List<String> strings = new ArrayList<String>();\r
Properties props = getSettings();\r
return strings;\r
}\r
\r
+ /**\r
+ * Override the specified key with the specified value.\r
+ * \r
+ * @param key\r
+ * @param value\r
+ */\r
public void overrideSetting(String key, String value) {\r
overrides.put(key, value);\r
}\r
\r
import com.gitblit.models.UserModel;\r
\r
+/**\r
+ * Implementations of IUserService control all aspects of UserModel objects and\r
+ * user authentication.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public interface IUserService {\r
\r
+ /**\r
+ * Does the user service support cookie authentication?\r
+ * \r
+ * @return true or false\r
+ */\r
boolean supportsCookies();\r
\r
+ /**\r
+ * Returns the cookie value for the specified user.\r
+ * \r
+ * @param model\r
+ * @return cookie value\r
+ */\r
char[] getCookie(UserModel model);\r
\r
+ /**\r
+ * Authenticate a user based on their cookie.\r
+ * \r
+ * @param cookie\r
+ * @return a user object or null\r
+ */\r
UserModel authenticate(char[] cookie);\r
\r
+ /**\r
+ * Authenticate a user based on a username and password.\r
+ * \r
+ * @param username\r
+ * @param password\r
+ * @return a user object or null\r
+ */\r
UserModel authenticate(String username, char[] password);\r
\r
+ /**\r
+ * Retrieve the user object for the specified username.\r
+ * \r
+ * @param username\r
+ * @return a user object or null\r
+ */\r
UserModel getUserModel(String username);\r
\r
+ /**\r
+ * Updates/writes a complete user object.\r
+ * \r
+ * @param model\r
+ * @return true if update is successful\r
+ */\r
boolean updateUserModel(UserModel model);\r
\r
+ /**\r
+ * Adds/updates a user object keyed by username. This method allows for\r
+ * renaming a user.\r
+ * \r
+ * @param username\r
+ * the old username\r
+ * @param model\r
+ * the user object to use for username\r
+ * @return true if update is successful\r
+ */\r
boolean updateUserModel(String username, UserModel model);\r
\r
+ /**\r
+ * Deletes the user object from the user service.\r
+ * \r
+ * @param model\r
+ * @return true if successful\r
+ */\r
boolean deleteUserModel(UserModel model);\r
\r
+ /**\r
+ * Delete the user object with the specified username\r
+ * \r
+ * @param username\r
+ * @return true if successful\r
+ */\r
boolean deleteUser(String username);\r
\r
+ /**\r
+ * Returns the list of all users available to the login service.\r
+ * \r
+ * @return list of all usernames\r
+ */\r
List<String> getAllUsernames();\r
\r
- List<String> getUsernamesForRepository(String role);\r
-\r
- boolean setUsernamesForRepository(String role, List<String> usernames);\r
-\r
+ /**\r
+ * Returns the list of all users who are allowed to bypass the access\r
+ * restriction placed on the specified repository.\r
+ * \r
+ * @param role\r
+ * the repository name\r
+ * @return list of all usernames that can bypass the access restriction\r
+ */\r
+ List<String> getUsernamesForRepositoryRole(String role);\r
+\r
+ /**\r
+ * Sets the list of all uses who are allowed to bypass the access\r
+ * restriction placed on the specified repository.\r
+ * \r
+ * @param role\r
+ * the repository name\r
+ * @param usernames\r
+ * @return true if successful\r
+ */\r
+ boolean setUsernamesForRepositoryRole(String role, List<String> usernames);\r
+\r
+ /**\r
+ * Renames a repository role.\r
+ * \r
+ * @param oldRole\r
+ * @param newRole\r
+ * @return true if successful\r
+ */\r
boolean renameRepositoryRole(String oldRole, String newRole);\r
\r
+ /**\r
+ * Removes a repository role from all users.\r
+ * \r
+ * @param role\r
+ * @return true if successful\r
+ */\r
boolean deleteRepositoryRole(String role);\r
\r
+ /**\r
+ * @See java.lang.Object.toString();\r
+ * @return string representation of the login service\r
+ */\r
String toString();\r
}\r
import com.gitblit.build.Build;\r
\r
/**\r
- * Launch helper class that adds all jars found in the local "lib" folder and\r
- * then calls the application main. Using this technique we do not have to\r
- * specify a classpath and we can dynamically add jars to the distribution.\r
+ * Launch helper class that adds all jars found in the local "lib" & "ext"\r
+ * folders and then calls the application main. Using this technique we do not\r
+ * have to specify a classpath and we can dynamically add jars to the\r
+ * distribution.\r
+ * \r
+ * This class also downloads all runtime dependencies, if they are not found.\r
+ * \r
+ * @author James Moger\r
* \r
*/\r
public class Launcher {\r
+ protectionDomain.getCodeSource().getLocation().toExternalForm());\r
}\r
\r
+ // download all runtime dependencies\r
Build.runtime();\r
\r
// Load the JARs in the lib and ext folder\r
import com.beust.jcommander.Parameters;\r
import com.gitblit.utils.TimeUtils;\r
\r
+/**\r
+ * Utility class to generate self-signed certificates.\r
+ * \r
+ * @author James Moger\r
+ *\r
+ */\r
public class MakeCertificate {\r
\r
private static final String BC = org.bouncycastle.jce.provider.BouncyCastleProvider.PROVIDER_NAME;\r
import javax.servlet.http.HttpServletRequest;\r
import javax.servlet.http.HttpSession;\r
\r
+/**\r
+ * ServletRequestWrapper is a pass-through/delegate wrapper class for a servlet\r
+ * request. This class is used in conjunction with ServletFilters, such as the\r
+ * AccessRestrictionFilter.\r
+ * \r
+ * The original request is wrapped by instances of this class and this class is\r
+ * set as the servlet request in the filter. This allows for specialized\r
+ * implementations of request methods, like getUserPrincipal() with delegation\r
+ * to the original request for any method not overridden.\r
+ * \r
+ * This class, by itself, is not altogether interesting. Subclasses of this\r
+ * class, however, are of interest.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public abstract class ServletRequestWrapper implements HttpServletRequest {\r
\r
protected final HttpServletRequest req;\r
import com.gitblit.models.RepositoryModel;\r
import com.gitblit.models.UserModel;\r
\r
+/**\r
+ * The SyndicationFilter is an AccessRestrictionFilter which ensures that feed\r
+ * requests for view-restricted repositories have proper authentication\r
+ * credentials and are authorized for the requested feed.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class SyndicationFilter extends AccessRestrictionFilter {\r
\r
+ /**\r
+ * Extract the repository name from the url.\r
+ * \r
+ * @param url\r
+ * @return repository name\r
+ */\r
@Override\r
protected String extractRepositoryName(String url) {\r
return url;\r
}\r
\r
+ /**\r
+ * Analyze the url and returns the action of the request.\r
+ * \r
+ * @param url\r
+ * @return action of the request\r
+ */\r
@Override\r
- protected String getUrlRequestType(String url) {\r
- return "RESTRICTED";\r
+ protected String getUrlRequestAction(String url) {\r
+ return "VIEW";\r
}\r
\r
+ /**\r
+ * Determine if the repository requires authentication.\r
+ * \r
+ * @param repository\r
+ * @return true if authentication required\r
+ */\r
@Override\r
protected boolean requiresAuthentication(RepositoryModel repository) {\r
return repository.accessRestriction.atLeast(AccessRestrictionType.VIEW);\r
}\r
\r
+ /**\r
+ * Determine if the user can access the repository and perform the specified\r
+ * action.\r
+ * \r
+ * @param repository\r
+ * @param user\r
+ * @param action\r
+ * @return true if user may execute the action on the repository\r
+ */\r
@Override\r
- protected boolean canAccess(RepositoryModel repository, UserModel user, String restrictedURL) {\r
+ protected boolean canAccess(RepositoryModel repository, UserModel user, String action) {\r
return user.canAccessRepository(repository.name);\r
}\r
\r
import com.gitblit.utils.SyndicationUtils;\r
import com.gitblit.wicket.WicketUtils;\r
\r
+/**\r
+ * SyndicationServlet generates RSS 2.0 feeds and feed links.\r
+ * \r
+ * Access to this servlet is protected by the SyndicationFilter.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class SyndicationServlet extends HttpServlet {\r
\r
private static final long serialVersionUID = 1L;\r
\r
private transient Logger logger = LoggerFactory.getLogger(SyndicationServlet.class);\r
\r
+ /**\r
+ * Create a feed link for the specified repository and branch/tag/commit id.\r
+ * \r
+ * @param baseURL\r
+ * @param repository\r
+ * the repository name\r
+ * @param objectId\r
+ * the branch, tag, or first commit for the feed\r
+ * @param length\r
+ * the number of commits to include in the feed\r
+ * @return an RSS feed url\r
+ */\r
public static String asLink(String baseURL, String repository, String objectId, int length) {\r
if (baseURL.length() > 0 && baseURL.charAt(baseURL.length() - 1) == '/') {\r
baseURL = baseURL.substring(0, baseURL.length() - 1);\r
return url.toString();\r
}\r
\r
+ /**\r
+ * Determines the appropriate title for a feed.\r
+ * \r
+ * @param repository\r
+ * @param objectId\r
+ * @return title of the feed\r
+ */\r
public static String getTitle(String repository, String objectId) {\r
String id = objectId;\r
if (!StringUtils.isEmpty(id)) {\r
return MessageFormat.format("{0} ({1})", repository, id);\r
}\r
\r
+ /**\r
+ * Generates the feed content.\r
+ * \r
+ * @param request\r
+ * @param response\r
+ * @throws javax.servlet.ServletException\r
+ * @throws java.io.IOException\r
+ */\r
private void processRequest(javax.servlet.http.HttpServletRequest request,\r
javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,\r
java.io.IOException {\r
\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * Loads Gitblit settings from the context-parameter values of a web.xml file.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class WebXmlSettings extends IStoredSettings {\r
\r
private final Properties properties = new Properties();\r
logger.debug(key + "=" + properties.getProperty(key));\r
}\r
}\r
- \r
+\r
private String decodeValue(String value) {\r
- // Decode escaped backslashes and HTML entities\r
+ // decode escaped backslashes and HTML entities\r
return StringUtils.decodeFromHtml(value).replace("\\\\", "\\");\r
}\r
\r
import com.gitblit.Constants;\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * The Build class downloads runtime and compile-time jar files from the Apache\r
+ * or Eclipse Maven repositories.\r
+ * \r
+ * It also generates the Keys class from the gitblit.properties file.\r
+ * \r
+ * Its important that this class have minimal compile dependencies since its\r
+ * called very early in the build script.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class Build {\r
\r
public static enum BuildType {\r
downloadFromApache(MavenObject.COMMONSNET, BuildType.RUNTIME);\r
}\r
\r
+ /**\r
+ * Builds the Keys class based on the gitblit.properties file and inserts\r
+ * the class source into the project source folder.\r
+ */\r
public static void buildSettingKeys() {\r
// Load all keys\r
Properties properties = new Properties();\r
*/\r
package com.gitblit.build;\r
\r
-import java.io.BufferedReader;\r
import java.io.File;\r
import java.io.FileInputStream;\r
import java.io.FileOutputStream;\r
import com.beust.jcommander.ParameterException;\r
import com.beust.jcommander.Parameters;\r
import com.gitblit.Constants;\r
+import com.gitblit.utils.FileUtils;\r
import com.gitblit.utils.MarkdownUtils;\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * Builds the web site or deployment documentation from Markdown source files.\r
+ * \r
+ * All Markdown source files must have the .mkd extension.\r
+ * \r
+ * Natural string sort order of the Markdown source filenames is the order of\r
+ * page links. "##_" prefixes are used to control the sort order.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class BuildSite {\r
\r
public static void main(String... args) {\r
sb.setLength(sb.length() - 3);\r
sb.trimToSize();\r
\r
- String htmlHeader = readContent(new File(params.pageHeader), "\n");\r
- String htmlFooter = readContent(new File(params.pageFooter), "\n");\r
+ String htmlHeader = FileUtils.readContent(new File(params.pageHeader), "\n");\r
+ String htmlFooter = FileUtils.readContent(new File(params.pageFooter), "\n");\r
final String links = sb.toString();\r
final String header = MessageFormat.format(htmlHeader, Constants.FULL_NAME, links);\r
final String date = new SimpleDateFormat("yyyy-MM-dd").format(new Date());\r
}\r
for (String alias : params.loads) {\r
String[] kv = alias.split("=");\r
- String loadedContent = readContent(new File(kv[1]), "\n");\r
+ String loadedContent = FileUtils.readContent(new File(kv[1]), "\n");\r
loadedContent = StringUtils.escapeForHtml(loadedContent, false);\r
loadedContent = StringUtils.breakLinesForHtml(loadedContent);\r
content = content.replace(kv[0], loadedContent);\r
}\r
}\r
\r
- private static String readContent(File file, String lineEnding) {\r
- StringBuilder sb = new StringBuilder();\r
- try {\r
- InputStreamReader is = new InputStreamReader(new FileInputStream(file),\r
- Charset.forName("UTF-8"));\r
- BufferedReader reader = new BufferedReader(is);\r
- String line = null;\r
- while ((line = reader.readLine()) != null) {\r
- sb.append(line);\r
- if (lineEnding != null) {\r
- sb.append(lineEnding);\r
- }\r
- }\r
- reader.close();\r
- } catch (Throwable t) {\r
- System.err.println("Failed to read content of " + file.getAbsolutePath());\r
- t.printStackTrace();\r
- }\r
- return sb.toString();\r
- }\r
-\r
private static String getDocumentName(File file) {\r
String displayName = file.getName().substring(0, file.getName().lastIndexOf('.'))\r
.toLowerCase();\r
- // trim leading ##_ which is to control display order\r
- return displayName.substring(3);\r
+ int underscore = displayName.indexOf('_') + 1;\r
+ if (underscore > -1) {\r
+ // trim leading ##_ which is to control display order\r
+ return displayName.substring(underscore);\r
+ }\r
+ return displayName;\r
}\r
\r
private static void usage(JCommander jc, ParameterException t) {\r
import java.io.FileOutputStream;\r
import java.io.FilenameFilter;\r
import java.io.IOException;\r
+import java.text.MessageFormat;\r
import java.util.Iterator;\r
\r
import javax.imageio.ImageIO;\r
import com.beust.jcommander.ParameterException;\r
import com.beust.jcommander.Parameters;\r
\r
+/**\r
+ * Generates PNG thumbnails of the PNG images from the specified source folder.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class BuildThumbnails {\r
\r
public static void main(String[] args) {\r
createImageThumbnail(params.sourceFolder, params.destinationFolder, params.maximumDimension);\r
}\r
\r
+ /**\r
+ * Generates thumbnails from all PNG images in the source folder and saves\r
+ * them to the destination folder.\r
+ * \r
+ * @param sourceFolder\r
+ * @param destinationFolder\r
+ * @param maxDimension\r
+ * the maximum height or width of the image.\r
+ */\r
public static void createImageThumbnail(String sourceFolder, String destinationFolder,\r
int maxDimension) {\r
if (maxDimension <= 0)\r
// Scale to Width\r
w = maxDimension;\r
float f = maxDimension;\r
- h = (int) ((f / sz.width) * sz.height); // normalize height\r
+ // normalize height\r
+ h = (int) ((f / sz.width) * sz.height);\r
} else if (sz.height > maxDimension) {\r
// Scale to Height\r
h = maxDimension;\r
float f = maxDimension;\r
- w = (int) ((f / sz.height) * sz.width); // normalize width\r
- } else {\r
- // No thumbnail\r
- return;\r
+ // normalize width\r
+ w = (int) ((f / sz.height) * sz.width);\r
}\r
- System.out.println("Generating thumbnail for " + sourceFile.getName() + " as (" + w\r
- + "," + h + ")");\r
+ System.out.println(MessageFormat.format(\r
+ "Generating thumbnail for {0} as ({1,number,#}, {2,number,#})",\r
+ sourceFile.getName(), w, h));\r
BufferedImage image = ImageIO.read(sourceFile);\r
Image scaledImage = image.getScaledInstance(w, h, BufferedImage.SCALE_SMOOTH);\r
BufferedImage destImage = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);\r
}\r
}\r
\r
+ /**\r
+ * Return the dimensions of the specified image file.\r
+ * \r
+ * @param file\r
+ * @return dimensions of the image\r
+ * @throws IOException\r
+ */\r
public static Dimension getImageDimensions(File file) throws IOException {\r
ImageInputStream in = ImageIO.createImageInputStream(file);\r
try {\r
import com.beust.jcommander.ParameterException;\r
import com.beust.jcommander.Parameters;\r
import com.gitblit.Keys;\r
-import com.gitblit.Keys.server;\r
import com.gitblit.utils.StringUtils;\r
\r
+/**\r
+ * Builds the Gitblit WAR web.xml file by merging the Gitblit GO web.xml file\r
+ * with the gitblit.properties comments, settings, and values.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
public class BuildWebXml {\r
private static final String PARAMS = "<!-- PARAMS -->";\r
\r
for (String comment : setting.comments) {\r
parameters.append(MessageFormat.format(COMMENT_PATTERN, comment));\r
}\r
- parameters.append(MessageFormat.format(PARAM_PATTERN, setting.name, StringUtils.escapeForHtml(setting.value, false)));\r
+ parameters.append(MessageFormat.format(PARAM_PATTERN, setting.name,\r
+ StringUtils.escapeForHtml(setting.value, false)));\r
}\r
\r
// Read the prototype web.xml file\r
--- /dev/null
+/*\r
+ * Copyright 2011 gitblit.com.\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+package com.gitblit.utils;\r
+\r
+import java.io.BufferedReader;\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.InputStreamReader;\r
+import java.nio.charset.Charset;\r
+\r
+/**\r
+ * Common file utilities.\r
+ * \r
+ * @author James Moger\r
+ * \r
+ */\r
+public class FileUtils {\r
+\r
+ /**\r
+ * Returns the string content of the specified file.\r
+ * \r
+ * @param file\r
+ * @param lineEnding\r
+ * @return\r
+ */\r
+ public static String readContent(File file, String lineEnding) {\r
+ StringBuilder sb = new StringBuilder();\r
+ try {\r
+ InputStreamReader is = new InputStreamReader(new FileInputStream(file),\r
+ Charset.forName("UTF-8"));\r
+ BufferedReader reader = new BufferedReader(is);\r
+ String line = null;\r
+ while ((line = reader.readLine()) != null) {\r
+ sb.append(line);\r
+ if (lineEnding != null) {\r
+ sb.append(lineEnding);\r
+ }\r
+ }\r
+ reader.close();\r
+ } catch (Throwable t) {\r
+ System.err.println("Failed to read content of " + file.getAbsolutePath());\r
+ t.printStackTrace();\r
+ }\r
+ return sb.toString();\r
+ }\r
+}\r
}\r
\r
// save the repository\r
- GitBlit.self().editRepositoryModel(oldName, repositoryModel, isCreate);\r
+ GitBlit.self().updateRepositoryModel(oldName, repositoryModel, isCreate);\r
\r
// save the repository access list\r
if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {\r
userModel.repositories.clear();\r
userModel.repositories.addAll(repos);\r
try {\r
- GitBlit.self().editUserModel(oldName, userModel, isCreate);\r
+ GitBlit.self().updateUserModel(oldName, userModel, isCreate);\r
} catch (GitBlitException e) {\r
error(e.getMessage());\r
return;\r
try {\r
RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName);\r
model.useTickets = true;\r
- GitBlit.self().editRepositoryModel(model.name, model, false);\r
+ GitBlit.self().updateRepositoryModel(model.name, model, false);\r
} catch (GitBlitException g) {\r
g.printStackTrace();\r
}\r
try {\r
RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName);\r
model.useDocs = true;\r
- GitBlit.self().editRepositoryModel(model.name, model, false);\r
+ GitBlit.self().updateRepositoryModel(model.name, model, false);\r
} catch (GitBlitException g) {\r
g.printStackTrace();\r
}\r
try {\r
RepositoryModel model = GitBlit.self().getRepositoryModel(repositoryName);\r
model.showRemoteBranches = true;\r
- GitBlit.self().editRepositoryModel(model.name, model, false);\r
+ GitBlit.self().updateRepositoryModel(model.name, model, false);\r
} catch (GitBlitException g) {\r
g.printStackTrace();\r
}\r