diff options
30 files changed, 703 insertions, 97 deletions
@@ -4,3 +4,4 @@ /build /keystore /gitblit.zip +/gitblit-0.1.0-SNAPSHOT.zip @@ -3,12 +3,35 @@ <!-- Project Properties -->
<property name="project.jar" value="gitblit.jar" />
- <property name="project.mainclass" value="com.gitblit.Launcher" />
- <property name="distribution.zipfile" value="gitblit.zip" />
+ <property name="project.mainclass" value="com.gitblit.Launcher" />
<property name="project.build.dir" value="${basedir}/build" />
<target name="main">
-
+
+ <!-- extract version number from source code -->
+ <loadfile property="gb.version" srcfile="${basedir}/src/com/gitblit/Constants.java">
+ <filterchain>
+ <linecontains>
+ <contains value="public final static String VERSION = "/>
+ </linecontains>
+ <striplinebreaks/>
+ <tokenfilter>
+ <replacestring from="public final static String VERSION = "" to=""/>
+ <replacestring from="";" to=""/>
+ <trim />
+ </tokenfilter>
+ </filterchain>
+ </loadfile>
+ <echo>Building Git:Blit ${gb.version}</echo>
+
+ <!-- copy required distribution files to project folder -->
+ <copy todir="${basedir}" overwrite="false">
+ <fileset dir="${basedir}/distrib">
+ <include name="gitblit.properties" />
+ <include name="users.properties" />
+ </fileset>
+ </copy>
+
<!-- Compile the build tool and execute it.
This downloads missing compile-time dependencies from Maven. -->
@@ -53,16 +76,13 @@ <mkdir dir="${basedir}/deploy" />
<copy todir="${basedir}/deploy" file="${project.jar}" />
<copy todir="${basedir}/deploy">
- <fileset dir="${basedir}/service">
+ <fileset dir="${basedir}/distrib">
<include name="**/*" />
</fileset>
- <fileset dir="${basedir}">
- <include name="*.cmd" />
- <include name="*.properties" />
- </fileset>
</copy>
<!-- Create Zip deployment -->
+ <property name="distribution.zipfile" value="gitblit-${gb.version}.zip" />
<zip destfile="${distribution.zipfile}">
<fileset dir="${basedir}/deploy">
<include name="**/*" />
diff --git a/service/JavaService.exe b/distrib/JavaService.exe Binary files differindex 87559550..87559550 100644 --- a/service/JavaService.exe +++ b/distrib/JavaService.exe diff --git a/service/JavaService64.exe b/distrib/JavaService64.exe Binary files differindex fb327085..fb327085 100644 --- a/service/JavaService64.exe +++ b/distrib/JavaService64.exe diff --git a/service/UninstallService.bat b/distrib/UninstallService.bat index a483c55d..a483c55d 100644 --- a/service/UninstallService.bat +++ b/distrib/UninstallService.bat diff --git a/service/UninstallService64.bat b/distrib/UninstallService64.bat index 91f0c840..91f0c840 100644 --- a/service/UninstallService64.bat +++ b/distrib/UninstallService64.bat diff --git a/distrib/gitblit-stop.cmd b/distrib/gitblit-stop.cmd new file mode 100644 index 00000000..c139d57b --- /dev/null +++ b/distrib/gitblit-stop.cmd @@ -0,0 +1 @@ +@java -jar gitblit.jar --stop
diff --git a/distrib/gitblit.cmd b/distrib/gitblit.cmd new file mode 100644 index 00000000..ce96a797 --- /dev/null +++ b/distrib/gitblit.cmd @@ -0,0 +1 @@ +@java -jar gitblit.jar
diff --git a/distrib/gitblit.properties b/distrib/gitblit.properties new file mode 100644 index 00000000..6bf33f13 --- /dev/null +++ b/distrib/gitblit.properties @@ -0,0 +1,159 @@ +#
+# Git Servlet Settings
+#
+
+# Allow push/pull over http/https with JGit servlet
+git.enableGitServlet = true
+
+# Base folder for repositories
+# Use forward slashes even on Windows!!
+git.repositoriesFolder = c:/git
+
+# Export all repositories
+# if false, each exported repository must have a .git/git-daemon-export-ok file
+git.exportAll = true
+
+# Search repositories folder for nested repositories
+# e.g. /libraries/mylibrary.git
+git.nestedRepositories = true
+
+# The root clone url
+git.cloneUrl = https://localhost/git/
+
+#
+# Authentication Settings
+#
+
+# Require authentication to see everything but the admin pages
+web.authenticateViewPages = false
+
+# Require admin authentication for the admin functions and pages
+web.authenticateAdminPages = true
+
+# Simple user realm file to authenticate users
+realm.realmFile = users.properties
+
+# How to store passwords.
+# Valid values are plain, md5 or crypt (unix style). Default is md5.
+realm.passwordStorage = md5
+
+#
+# Git:Blit Web Settings
+#
+# If blank Git:Blit is displayed.
+web.siteName =
+
+# If web.authenticate=true, users with "admin" role can create repositories,
+# create users, and edit repository metadata (owner, description, etc)
+#
+# If web.authenticate=false, any user can execute the aforementioned functions.
+web.allowAdministration = true
+
+# This is the message display above the repositories table.
+# This can point to a file with Markdown content.
+# Specifying "gitblit" uses the internal welcome message.
+web.repositoriesMessage = gitblit
+
+# Use the client timezone when formatting dates.
+# This uses AJAX to determine the browser's timezone.
+web.useClientTimezone = false
+
+# Date and Time formats
+web.datestampShortFormat = yyyy-MM-dd
+web.datetimestampLongFormat = EEEE, MMMM d, yyyy h:mm a z
+
+# Choose the diff presentation style: gitblt, gitweb, or plain
+web.diffStyle = gitblit
+
+# Control if email addresses are shown in web ui
+web.showEmailAddresses = true
+
+# Shows a combobox in the page links header with commit, committer, and author
+# search selection. Default search is commit.
+web.showSearchTypeSelection = false
+
+# Generates a line graph of repository activity over time on the Summary page.
+# This is a real-time graph so generation may be expensive.
+web.generateActivityGraph = true
+
+# The number of commits to display on the summary page
+# Value must exceed 0 else default of 20 is used
+web.summaryCommitCount = 16
+
+# The number of tags/heads to display on the summary page
+# Value must exceed 0 else default of 5 is used
+web.summaryRefsCount = 5
+
+# The number of items to show on a page before showing the first, prev, next
+# pagination links. A default if 50 is used for any invalid value.
+web.itemsPerPage = 50
+
+# Registered extensions for google-code-prettify
+web.prettyPrintExtensions = c cpp cs css htm html java js php pl prefs properties py rb sh sql xml vb
+
+# Registered extensions for markdown transformation
+web.markdownExtensions = md mkd markdown
+
+# Image extensions
+web.imageExtensions = bmp jpg gif png
+
+# Registered extensions for binary blobs
+web.binaryExtensions = jar pdf tar.gz zip
+
+# Aggressive heap management will run the garbage collector on every generated
+# page. This slows down page generation but improves heap consumption.
+web.aggressiveHeapManagement = true
+
+# Run the webapp in debug mode
+web.debugMode = false
+
+# Enable/disable global regex substitutions (i.e. shared across repositories)
+regex.global = true
+
+# Example global regex substitutions
+# Use !!! to separate the search pattern and the replace pattern
+# searchpattern!!!replacepattern
+#regex.global.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!<a href="http://somehost/bug/$3">Bug-Id: $3</a>
+#regex.global.changeid = \\b(Change-Id:\\s*)([A-Za-z0-9]*)\\b!!!<a href="http://somehost/changeid/$2">Change-Id: $2</a>
+
+# Example per-repository regex substitutions overrides global
+#regex.myrepository.bug = \\b(Bug:)(\\s*[#]?|-){0,1}(\\d+)\\b!!!<a href="http://elsewhere/bug/$3">Bug-Id: $3</a>
+
+#
+# Server Settings
+#
+server.tempFolder = temp
+server.log4jPattern = %-5p %d{MM-dd HH:mm:ss.SSS} %-20.20c{1} %m%n
+server.log4jPattern.windows = %-5p %m%n
+server.log4jPattern.linux =
+
+
+#
+# Jetty Settings
+#
+
+# Use Jetty NIO connectors. If false, Jetty Socket connectors will be used.
+server.useNio = true
+
+# Standard http port to serve. <= 0 disables this connector.
+server.httpPort = 0
+
+# Secure/SSL https port to serve. <= 0 disables this connector.
+server.httpsPort = 443
+
+# Specify the interface for Jetty to bind the standard connector.
+# You may specify an ip or an empty value to bind to all interfaces.
+server.httpBindInterface = localhost
+
+# Specify the interface for Jetty to bind the secure connector.
+# You may specify an ip or an empty value to bind to all interfaces.
+server.httpsBindInterface = localhost
+
+# Password for SSL keystore.
+# Keystore password and certificate password must match.
+# This is provided for convenience, its probably more secure to set this value
+# using the --storePassword command line parameter.
+server.storePassword = dosomegit
+
+# Port for shutdown monitor to listen on.
+server.shutdownPort = 8081
diff --git a/service/installService.bat b/distrib/installService.bat index 5b0df2c6..5b0df2c6 100644 --- a/service/installService.bat +++ b/distrib/installService.bat diff --git a/service/installService64.bat b/distrib/installService64.bat index 08761f86..08761f86 100644 --- a/service/installService64.bat +++ b/distrib/installService64.bat diff --git a/distrib/makekeystore_jdk.cmd b/distrib/makekeystore_jdk.cmd new file mode 100644 index 00000000..34a11b21 --- /dev/null +++ b/distrib/makekeystore_jdk.cmd @@ -0,0 +1,2 @@ +@del keystore
+@keytool -keystore keystore -alias localhost -genkey -keyalg RSA -dname "CN=localhost, OU=Git:Blit, O=Git:Blit, L=Some Town, ST=Some State, C=US"
\ No newline at end of file diff --git a/distrib/users.properties b/distrib/users.properties new file mode 100644 index 00000000..920f3233 --- /dev/null +++ b/distrib/users.properties @@ -0,0 +1,2 @@ +# Git:Blit realm file format: username=password,\#permission,repository1,repository2...
+admin=admin,\#admin
diff --git a/gitblit.properties b/gitblit.properties index 2bdcf2c8..b9aae7cf 100644 --- a/gitblit.properties +++ b/gitblit.properties @@ -31,7 +31,11 @@ web.authenticateViewPages = false web.authenticateAdminPages = true
# Simple user realm file to authenticate users
-server.realmFile = users.properties
+realm.realmFile = users.properties
+
+# How to store passwords.
+# Valid values are plain, md5 or crypt (unix style). Default is md5.
+realm.passwordStorage = md5
#
# Git:Blit Web Settings
diff --git a/src/com/gitblit/Constants.java b/src/com/gitblit/Constants.java index 7d1758db..1b4a5188 100644 --- a/src/com/gitblit/Constants.java +++ b/src/com/gitblit/Constants.java @@ -4,6 +4,8 @@ public class Constants { public final static String NAME = "Git:Blit";
+ // The build script extracts this exact line so be careful editing it
+ // and only use A-Z a-z 0-9 .-_ in the string.
public final static String VERSION = "0.1.0-SNAPSHOT";
public final static String ADMIN_ROLE = "#admin";
@@ -21,23 +23,17 @@ public class Constants { }
return NONE;
}
-
+
+ public boolean exceeds(AccessRestrictionType type) {
+ return this.ordinal() > type.ordinal();
+ }
+
public boolean atLeast(AccessRestrictionType type) {
return this.ordinal() >= type.ordinal();
}
public String toString() {
- switch (this) {
- case NONE:
- return "Anonymous View, Clone, & Push";
- case PUSH:
- return "Anonymous View & Clone, Authenticated Push";
- case CLONE:
- return "Anonymous View, Authenticated Clone & Push";
- case VIEW:
- return "Authenticated View, Clone, & Push";
- }
- return "none";
+ return name();
}
}
diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java index 40cb3886..62ff55eb 100644 --- a/src/com/gitblit/GitBlit.java +++ b/src/com/gitblit/GitBlit.java @@ -95,11 +95,23 @@ public class GitBlit implements ServletContextListener { userCookie.setPath("/");
response.addCookie(userCookie);
}
+
+ public List<String> getAllUsernames() {
+ return loginService.getAllUsernames();
+ }
- public UserModel getUser(String username) {
+ public UserModel getUserModel(String username) {
UserModel user = loginService.getUserModel(username);
return user;
}
+
+ public List<String> getRepositoryUsers(RepositoryModel repository) {
+ return loginService.getUsernamesForRole(repository.name);
+ }
+
+ public boolean setRepositoryUsers(RepositoryModel repository, List<String> repositoryUsers) {
+ return loginService.setUsernamesForRole(repository.name, repositoryUsers);
+ }
public void editUserModel(UserModel user, boolean isCreate) throws GitBlitException {
if (!loginService.updateUserModel(user)) {
@@ -206,7 +218,7 @@ public class GitBlit implements ServletContextListener { }
public void configureContext(IStoredSettings settings) {
- logger.info("Configure GitBlit from " + settings.toString());
+ logger.info("Using configuration from " + settings.toString());
this.storedSettings = settings;
repositoriesFolder = new File(settings.getString(Keys.git.repositoriesFolder, "repos"));
exportAll = settings.getBoolean(Keys.git.exportAll, true);
diff --git a/src/com/gitblit/GitBlitServer.java b/src/com/gitblit/GitBlitServer.java index f5ed91aa..17b9e7a0 100644 --- a/src/com/gitblit/GitBlitServer.java +++ b/src/com/gitblit/GitBlitServer.java @@ -458,7 +458,7 @@ public class GitBlitServer { * Authentication Parameters
*/
@Parameter(names = { "--realmFile" }, description = "Users Realm Hash File")
- public String realmFile = fileSettings.getString(Keys.server.realmFile, "users.properties");
+ public String realmFile = fileSettings.getString(Keys.realm.realmFile, "users.properties");
/*
* JETTY Parameters
diff --git a/src/com/gitblit/ILoginService.java b/src/com/gitblit/ILoginService.java index d0c5d13d..242ff803 100644 --- a/src/com/gitblit/ILoginService.java +++ b/src/com/gitblit/ILoginService.java @@ -1,5 +1,7 @@ package com.gitblit;
+import java.util.List;
+
import com.gitblit.wicket.models.UserModel;
public interface ILoginService {
@@ -14,4 +16,14 @@ public interface ILoginService { boolean deleteUserModel(UserModel model);
+ List<String> getAllUsernames();
+
+ List<String> getUsernamesForRole(String role);
+
+ boolean setUsernamesForRole(String role, List<String> usernames);
+
+ boolean renameRole(String oldRole, String newRole);
+
+ boolean deleteRole(String role);
+
}
diff --git a/src/com/gitblit/JettyLoginService.java b/src/com/gitblit/JettyLoginService.java index 4b439647..fb510ee6 100644 --- a/src/com/gitblit/JettyLoginService.java +++ b/src/com/gitblit/JettyLoginService.java @@ -5,9 +5,13 @@ import java.io.FileReader; import java.io.FileWriter;
import java.io.IOException;
import java.security.Principal;
+import java.text.MessageFormat;
import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
import java.util.Map;
import java.util.Properties;
+import java.util.Set;
import javax.security.auth.Subject;
@@ -16,12 +20,16 @@ import org.eclipse.jetty.security.IdentityService; import org.eclipse.jetty.security.MappedLoginService;
import org.eclipse.jetty.server.UserIdentity;
import org.eclipse.jetty.util.log.Log;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.models.UserModel;
public class JettyLoginService extends MappedLoginService implements ILoginService {
+ private final Logger logger = LoggerFactory.getLogger(JettyLoginService.class);
+
private final File realmFile;
public JettyLoginService(File realmFile) {
@@ -44,8 +52,9 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi for (Principal principal : identity.getSubject().getPrincipals()) {
if (principal instanceof RolePrincipal) {
RolePrincipal role = (RolePrincipal) principal;
- if (role.getName().charAt(0) != '#') {
- user.addRepository(role.getName().substring(1));
+ String roleName = role.getName();
+ if (roleName.charAt(0) != '#') {
+ user.addRepository(roleName);
}
}
}
@@ -75,25 +84,29 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi }
break;
default:
- model.addRepository(name.substring(1));
+ model.addRepository(name);
}
}
}
+ // Retrieve the password from the realm file.
+ // Stupid, I know, but the password is buried within protected inner
+ // classes in private variables. Too much work to reflectively retrieve.
+ try {
+ Properties allUsers = readRealmFile();
+ String value = allUsers.getProperty(username);
+ String password = value.split(",")[0];
+ model.setPassword(password);
+ } catch (Throwable t) {
+ logger.error(MessageFormat.format("Failed to read password for user {0}!", username), t);
+ }
return model;
}
@Override
public boolean updateUserModel(UserModel model) {
try {
- Properties properties = new Properties();
- FileReader reader = new FileReader(realmFile);
- properties.load(reader);
- reader.close();
-
- ArrayList<String> roles = new ArrayList<String>();
-
- // Repositories
- roles.addAll(model.getRepositories());
+ Properties allUsers = readRealmFile();
+ ArrayList<String> roles = new ArrayList<String>(model.getRepositories());
// Permissions
if (model.canAdmin()) {
@@ -109,21 +122,15 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi }
// trim trailing comma
sb.setLength(sb.length() - 1);
+ allUsers.put(model.getUsername(), sb.toString());
- // Update realm file
- File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");
- FileWriter writer = new FileWriter(realmFileCopy);
- properties.put(model.getUsername(), sb.toString());
- properties.store(writer, null);
- writer.close();
- realmFile.delete();
- realmFileCopy.renameTo(realmFile);
+ writeRealmFile(allUsers);
// Update login service
putUser(model.getUsername(), Credential.getCredential(model.getPassword()), roles.toArray(new String[0]));
return true;
} catch (Throwable t) {
- t.printStackTrace();
+ logger.error(MessageFormat.format("Failed to update user model {0}!", model.getUsername()), t);
}
return false;
}
@@ -132,29 +139,258 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi public boolean deleteUserModel(UserModel model) {
try {
// Read realm file
- Properties properties = new Properties();
- FileReader reader = new FileReader(realmFile);
- properties.load(reader);
- reader.close();
- properties.remove(model.getUsername());
-
- // Update realm file
- File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");
- FileWriter writer = new FileWriter(realmFileCopy);
- properties.store(writer, null);
- writer.close();
- realmFile.delete();
- realmFileCopy.renameTo(realmFile);
+ Properties allUsers = readRealmFile();
+ allUsers.remove(model.getUsername());
+ writeRealmFile(allUsers);
// Drop user from map
_users.remove(model.getUsername());
return true;
} catch (Throwable t) {
- t.printStackTrace();
+ logger.error(MessageFormat.format("Failed to delete user model {0}!", model.getUsername()), t);
+ }
+ return false;
+ }
+
+ @Override
+ public List<String> getAllUsernames() {
+ List<String> list = new ArrayList<String>();
+ list.addAll(_users.keySet());
+ return list;
+ }
+
+ @Override
+ public List<String> getUsernamesForRole(String role) {
+ List<String> list = new ArrayList<String>();
+ try {
+ Properties allUsers = readRealmFile();
+ for (String username : allUsers.stringPropertyNames()) {
+ String value = allUsers.getProperty(username);
+ String[] values = value.split(",");
+ // skip first value (password)
+ for (int i = 1; i < values.length; i++) {
+ String r = values[i];
+ if (r.equalsIgnoreCase(role)) {
+ list.add(username);
+ break;
+ }
+ }
+ }
+ } catch (Throwable t) {
+ logger.error(MessageFormat.format("Failed to get usernames for role {0}!", role), t);
+ }
+ return list;
+ }
+
+ @Override
+ public boolean setUsernamesForRole(String role, List<String> usernames) {
+ try {
+ Set<String> specifiedUsers = new HashSet<String>(usernames);
+ Set<String> needsAddRole = new HashSet<String>(specifiedUsers);
+ Set<String> needsRemoveRole = new HashSet<String>();
+
+ // identify users which require add and remove role
+ Properties allUsers = readRealmFile();
+ for (String username : allUsers.stringPropertyNames()) {
+ String value = allUsers.getProperty(username);
+ String[] values = value.split(",");
+ // skip first value (password)
+ for (int i = 1; i < values.length; i++) {
+ String r = values[i];
+ if (r.equalsIgnoreCase(role)) {
+ // user has role, check against revised user list
+ if (specifiedUsers.contains(username)) {
+ needsAddRole.remove(username);
+ } else {
+ // remove role from user
+ needsRemoveRole.add(username);
+ }
+ break;
+ }
+ }
+ }
+
+ // add roles to users
+ for (String user : needsAddRole) {
+ String userValues = allUsers.getProperty(user);
+ userValues += ("," + role);
+ allUsers.put(user, userValues);
+ String[] values = userValues.split(",");
+ String password = values[0];
+ String[] roles = new String[values.length - 1];
+ System.arraycopy(values, 1, roles, 0, values.length - 1);
+ putUser(user, Credential.getCredential(password), roles);
+ }
+
+ // remove role from user
+ for (String user : needsRemoveRole) {
+ String[] values = allUsers.getProperty(user).split(",");
+ String password = values[0];
+ StringBuilder sb = new StringBuilder();
+ sb.append(password);
+ sb.append(',');
+ List<String> revisedRoles = new ArrayList<String>();
+ // skip first value (password)
+ for (int i = 1; i < values.length; i++) {
+ String value = values[i];
+ if (!value.equalsIgnoreCase(role)) {
+ revisedRoles.add(value);
+ sb.append(value);
+ sb.append(',');
+ }
+ }
+ sb.setLength(sb.length() - 1);
+
+ // update properties
+ allUsers.put(user, sb.toString());
+
+ // update memory
+ putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));
+ }
+
+ // persist changes
+ writeRealmFile(allUsers);
+ return true;
+ } catch (Throwable t) {
+ logger.error(MessageFormat.format("Failed to set usernames for role {0}!", role), t);
+ }
+ return false;
+ }
+
+ @Override
+ public boolean renameRole(String oldRole, String newRole) {
+ try {
+ Properties allUsers = readRealmFile();
+ Set<String> needsRenameRole = new HashSet<String>();
+
+ // identify users which require role rename
+ for (String username : allUsers.stringPropertyNames()) {
+ String value = allUsers.getProperty(username);
+ String[] roles = value.split(",");
+ // skip first value (password)
+ for (int i = 1; i < roles.length; i++) {
+ String r = roles[i];
+ if (r.equalsIgnoreCase(oldRole)) {
+ needsRenameRole.remove(username);
+ break;
+ }
+ }
+ }
+
+ // rename role for identified users
+ for (String user : needsRenameRole) {
+ String userValues = allUsers.getProperty(user);
+ String[] values = userValues.split(",");
+ String password = values[0];
+ StringBuilder sb = new StringBuilder();
+ sb.append(password);
+ sb.append(',');
+ List<String> revisedRoles = new ArrayList<String>();
+ revisedRoles.add(newRole);
+ // skip first value (password)
+ for (int i = 1; i < values.length; i++) {
+ String value = values[i];
+ if (!value.equalsIgnoreCase(oldRole)) {
+ revisedRoles.add(value);
+ sb.append(value);
+ sb.append(',');
+ }
+ }
+ sb.setLength(sb.length() - 1);
+
+ // update properties
+ allUsers.put(user, sb.toString());
+
+ // update memory
+ putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));
+ }
+
+ // persist changes
+ writeRealmFile(allUsers);
+ return true;
+ } catch (Throwable t) {
+ logger.error(MessageFormat.format("Failed to rename role {0} to {1}!", oldRole, newRole), t);
}
return false;
}
+ @Override
+ public boolean deleteRole(String role) {
+ try {
+ Properties allUsers = readRealmFile();
+ Set<String> needsDeleteRole = new HashSet<String>();
+
+ // identify users which require role rename
+ for (String username : allUsers.stringPropertyNames()) {
+ String value = allUsers.getProperty(username);
+ String[] roles = value.split(",");
+ // skip first value (password)
+ for (int i = 1; i < roles.length; i++) {
+ String r = roles[i];
+ if (r.equalsIgnoreCase(role)) {
+ needsDeleteRole.remove(username);
+ break;
+ }
+ }
+ }
+
+ // delete role for identified users
+ for (String user : needsDeleteRole) {
+ String userValues = allUsers.getProperty(user);
+ String[] values = userValues.split(",");
+ String password = values[0];
+ StringBuilder sb = new StringBuilder();
+ sb.append(password);
+ sb.append(',');
+ List<String> revisedRoles = new ArrayList<String>();
+ // skip first value (password)
+ for (int i = 1; i < values.length; i++) {
+ String value = values[i];
+ if (!value.equalsIgnoreCase(role)) {
+ revisedRoles.add(value);
+ sb.append(value);
+ sb.append(',');
+ }
+ }
+ sb.setLength(sb.length() - 1);
+
+ // update properties
+ allUsers.put(user, sb.toString());
+
+ // update memory
+ putUser(user, Credential.getCredential(password), revisedRoles.toArray(new String[0]));
+ }
+
+ // persist changes
+ writeRealmFile(allUsers);
+ } catch (Throwable t) {
+ logger.error(MessageFormat.format("Failed to delete role {0}!", role), t);
+ }
+ return false;
+ }
+
+ private Properties readRealmFile() throws IOException {
+ Properties allUsers = new Properties();
+ FileReader reader = new FileReader(realmFile);
+ allUsers.load(reader);
+ reader.close();
+ return allUsers;
+ }
+
+ private void writeRealmFile(Properties properties) throws IOException {
+ // Update realm file
+ File realmFileCopy = new File(realmFile.getAbsolutePath() + ".tmp");
+ FileWriter writer = new FileWriter(realmFileCopy);
+ properties.store(writer, "# Git:Blit realm file format: username=password,\\#permission,repository1,repository2...");
+ writer.close();
+ if (realmFileCopy.exists() && realmFileCopy.length() > 0) {
+ realmFile.delete();
+ realmFileCopy.renameTo(realmFile);
+ } else {
+ throw new IOException("Failed to save realmfile!");
+ }
+ }
+
/* ------------------------------------------------------------ */
@Override
public void loadUsers() throws IOException {
@@ -163,13 +399,10 @@ public class JettyLoginService extends MappedLoginService implements ILoginServi if (Log.isDebugEnabled())
Log.debug("Load " + this + " from " + realmFile);
- Properties properties = new Properties();
- FileReader reader = new FileReader(realmFile);
- properties.load(reader);
- reader.close();
+ Properties allUsers = readRealmFile();
// Map Users
- for (Map.Entry<Object, Object> entry : properties.entrySet()) {
+ for (Map.Entry<Object, Object> entry : allUsers.entrySet()) {
String username = ((String) entry.getKey()).trim();
String credentials = ((String) entry.getValue()).trim();
String roles = null;
diff --git a/src/com/gitblit/wicket/BasePage.java b/src/com/gitblit/wicket/BasePage.java index 6125f2a0..733f4f7a 100644 --- a/src/com/gitblit/wicket/BasePage.java +++ b/src/com/gitblit/wicket/BasePage.java @@ -1,5 +1,7 @@ package com.gitblit.wicket;
+import java.util.LinkedHashMap;
+import java.util.Map;
import java.util.TimeZone;
import javax.servlet.http.HttpServletRequest;
@@ -14,6 +16,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory;
import com.gitblit.Constants;
+import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
import com.gitblit.wicket.pages.SummaryPage;
@@ -68,6 +71,27 @@ public abstract class BasePage extends WebPage { }
}
+ protected Map<AccessRestrictionType, String> getAccessRestrictions() {
+ Map<AccessRestrictionType, String> map = new LinkedHashMap<AccessRestrictionType, String>();
+ for (AccessRestrictionType type : AccessRestrictionType.values()) {
+ switch (type) {
+ case NONE:
+ map.put(type, getString("gb.notRestricted"));
+ break;
+ case PUSH:
+ map.put(type, getString("gb.pushRestricted"));
+ break;
+ case CLONE:
+ map.put(type, getString("gb.cloneRestricted"));
+ break;
+ case VIEW:
+ map.put(type, getString("gb.viewRestricted"));
+ break;
+ }
+ }
+ return map;
+ }
+
protected TimeZone getTimeZone() {
return GitBlit.self().settings().getBoolean(Keys.web.useClientTimezone, false) ? GitBlitWebSession.get().getTimezone() : TimeZone.getDefault();
}
diff --git a/src/com/gitblit/wicket/GitBlitWebApp.properties b/src/com/gitblit/wicket/GitBlitWebApp.properties index f2fe2327..3fe24d0a 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.properties +++ b/src/com/gitblit/wicket/GitBlitWebApp.properties @@ -80,9 +80,14 @@ gb.showRemoteBranches = show remote branches gb.editUsers = edit users
gb.password = password
gb.confirmPassword = confirm password
-gb.repositories = repositories
+gb.restrictedRepositories = restricted repositories
gb.canAdmin can admin
-gb.notRestricted = open repository
-gb.cloneRestricted = clone-restricted repository
-gb.pushRestricted = push-restricted repository
-gb.viewRestricted = view-restricted repository
\ No newline at end of file +gb.notRestricted = anonymous view, clone, & push
+gb.pushRestricted = authenticated push
+gb.cloneRestricted = authenticated clone & push
+gb.viewRestricted = authenticated view, clone, & push
+gb.useTicketsDescription = distributed Ticgit issues
+gb.useDocsDescription = enumerates Markdown documentation in repository
+gb.showRemoteBranchesDescription = show remote branches
+gb.canAdminDescription = can administer Git:Blit server
+gb.permittedUsers = permitted users
\ No newline at end of file diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.html b/src/com/gitblit/wicket/pages/EditRepositoryPage.html index 58723475..db5ab229 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.html +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.html @@ -18,10 +18,11 @@ <tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input type="text" wicket:id="name" id="name" size="40" tabindex="1" /></td></tr>
<tr><th><wicket:message key="gb.description"></wicket:message></th><td class="edit"><input type="text" wicket:id="description" size="40" tabindex="2" /></td></tr>
<tr><th><wicket:message key="gb.owner"></wicket:message></th><td class="edit"><input type="text" wicket:id="owner" size="40" tabindex="3" /></td></tr>
- <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select wicket:id="accessRestriction" tabindex="4" /></td></tr>
- <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="5" /> <i>distributed Ticgit issues</i></td></tr>
- <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="6" /> <i>enumerates Markdown documentation in repository</i></td></tr>
- <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="7" /> <i>show remote branches</i></td></tr>
+ <tr><th><wicket:message key="gb.enableTickets"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useTickets" tabindex="4" /> <i><wicket:message key="gb.useTicketsDescription"></wicket:message></i></td></tr>
+ <tr><th><wicket:message key="gb.enableDocs"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="useDocs" tabindex="5" /> <i><wicket:message key="gb.useDocsDescription"></wicket:message></i></td></tr>
+ <tr><th><wicket:message key="gb.showRemoteBranches"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="showRemoteBranches" tabindex="6" /> <i><wicket:message key="gb.showRemoteBranchesDescription"></wicket:message></i></td></tr>
+ <tr><th><wicket:message key="gb.accessRestriction"></wicket:message></th><td class="edit"><select wicket:id="accessRestriction" tabindex="7" /></td></tr>
+ <tr><th style="vertical-align: top;"><wicket:message key="gb.permittedUsers"></wicket:message></th><td style="padding:2px;"><span wicket:id="users"></span></td></tr>
<tr><th></th><td class="editButton"><input type="submit" value="Save" wicket:message="value:gb.save" tabindex="8" /></td></tr>
</tbody>
</table>
diff --git a/src/com/gitblit/wicket/pages/EditRepositoryPage.java b/src/com/gitblit/wicket/pages/EditRepositoryPage.java index 2d2b0ae2..8eed0059 100644 --- a/src/com/gitblit/wicket/pages/EditRepositoryPage.java +++ b/src/com/gitblit/wicket/pages/EditRepositoryPage.java @@ -1,18 +1,29 @@ package com.gitblit.wicket.pages;
+import java.text.MessageFormat;
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import org.apache.wicket.PageParameters;
+import org.apache.wicket.extensions.markup.html.form.palette.Palette;
import org.apache.wicket.markup.html.form.CheckBox;
+import org.apache.wicket.markup.html.form.ChoiceRenderer;
import org.apache.wicket.markup.html.form.DropDownChoice;
import org.apache.wicket.markup.html.form.Form;
+import org.apache.wicket.markup.html.form.IChoiceRenderer;
import org.apache.wicket.markup.html.form.TextField;
import org.apache.wicket.model.CompoundPropertyModel;
+import org.apache.wicket.model.util.CollectionModel;
+import org.apache.wicket.model.util.ListModel;
import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.GitBlit;
import com.gitblit.GitBlitException;
+import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.AdminPage;
import com.gitblit.wicket.BasePage;
import com.gitblit.wicket.WicketUtils;
@@ -40,11 +51,17 @@ public class EditRepositoryPage extends BasePage { }
protected void setupPage(final RepositoryModel repositoryModel) {
+ List<String> repositoryUsers = new ArrayList<String>();
if (isCreate) {
super.setupPage("", getString("gb.newRepository"));
} else {
- super.setupPage("", getString("gb.edit") + " " + repositoryModel.name);
+ super.setupPage("", getString("gb.edit"));
+ if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {
+ repositoryUsers.addAll(GitBlit.self().getRepositoryUsers(repositoryModel));
+ }
}
+
+ final Palette<String> usersPalette = new Palette<String>("users", new ListModel<String>(repositoryUsers), new CollectionModel<String>(GitBlit.self().getAllUsernames()), new ChoiceRenderer<String>("", ""), 10, false);
CompoundPropertyModel<RepositoryModel> model = new CompoundPropertyModel<RepositoryModel>(repositoryModel);
Form<RepositoryModel> form = new Form<RepositoryModel>("editForm", model) {
@@ -53,7 +70,48 @@ public class EditRepositoryPage extends BasePage { @Override
protected void onSubmit() {
try {
+ // confirm a repository name was entered
+ if (StringUtils.isEmpty(repositoryModel.name)) {
+ error("Please set repository name!");
+ return;
+ }
+
+ // automatically convert backslashes to forward slashes
+ repositoryModel.name = repositoryModel.name.replace('\\', '/');
+
+ // confirm valid characters in repository name
+ char[] validChars = { '/', '.', '_', '-' };
+ for (char c : repositoryModel.name.toCharArray()) {
+ if (!Character.isLetterOrDigit(c)) {
+ boolean ok = false;
+ for (char vc : validChars) {
+ ok |= c == vc;
+ }
+ if (!ok) {
+ error(MessageFormat.format("Illegal character '{0}' in repository name!", c));
+ return;
+ }
+ }
+ }
+
+ // confirm access restriction selection
+ if (repositoryModel.accessRestriction == null) {
+ error("Please select access restriction!");
+ return;
+ }
+
+ // save the repository
GitBlit.self().editRepositoryModel(repositoryModel, isCreate);
+
+ // save the repository access list
+ if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {
+ Iterator<String> users = usersPalette.getSelectedChoices();
+ List<String> repositoryUsers = new ArrayList<String>();
+ while (users.hasNext()) {
+ repositoryUsers.add(users.next());
+ }
+ GitBlit.self().setRepositoryUsers(repositoryModel, repositoryUsers);
+ }
} catch (GitBlitException e) {
error(e.getMessage());
return;
@@ -67,11 +125,33 @@ public class EditRepositoryPage extends BasePage { form.add(new TextField<String>("name").setEnabled(isCreate));
form.add(new TextField<String>("description"));
form.add(new TextField<String>("owner"));
- form.add(new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays.asList(AccessRestrictionType.values())));
+ form.add(new DropDownChoice<AccessRestrictionType>("accessRestriction", Arrays.asList(AccessRestrictionType.values()), new AccessRestrictionRenderer()));
form.add(new CheckBox("useTickets"));
form.add(new CheckBox("useDocs"));
form.add(new CheckBox("showRemoteBranches"));
+ form.add(usersPalette);
add(form);
}
+
+ private class AccessRestrictionRenderer implements IChoiceRenderer<AccessRestrictionType> {
+
+ private static final long serialVersionUID = 1L;
+
+ private final Map<AccessRestrictionType, String> map;
+
+ public AccessRestrictionRenderer() {
+ map = getAccessRestrictions();
+ }
+
+ @Override
+ public String getDisplayValue(AccessRestrictionType type) {
+ return map.get(type);
+ }
+
+ @Override
+ public String getIdValue(AccessRestrictionType type, int index) {
+ return Integer.toString(index);
+ }
+ }
}
diff --git a/src/com/gitblit/wicket/pages/EditUserPage.html b/src/com/gitblit/wicket/pages/EditUserPage.html index 57407d23..c50bdbac 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.html +++ b/src/com/gitblit/wicket/pages/EditUserPage.html @@ -18,8 +18,8 @@ <tr><th><wicket:message key="gb.name"></wicket:message></th><td class="edit"><input type="text" wicket:id="username" id="username" size="30" tabindex="1" /></td></tr>
<tr><th><wicket:message key="gb.password"></wicket:message></th><td class="edit"><input type="password" wicket:id="password" size="30" tabindex="2" /></td></tr>
<tr><th><wicket:message key="gb.confirmPassword"></wicket:message></th><td class="edit"><input type="password" wicket:id="confirmPassword" size="30" tabindex="3" /></td></tr>
- <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <i>can administer Git:Blit server</i></td></tr>
- <tr><th style="vertical-align: top;"><wicket:message key="gb.repositories"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr>
+ <tr><th><wicket:message key="gb.canAdmin"></wicket:message></th><td class="edit"><input type="checkbox" wicket:id="canAdmin" tabindex="6" /> <i><wicket:message key="gb.canAdminDescription"></wicket:message></i></td></tr>
+ <tr><th style="vertical-align: top;"><wicket:message key="gb.restrictedRepositories"></wicket:message></th><td style="padding:2px;"><span wicket:id="repositories"></span></td></tr>
<tr><th></th><td class="editButton"><input type="submit" value="Save" wicket:message="value:gb.save" tabindex="7" /></td></tr>
</tbody>
</table>
diff --git a/src/com/gitblit/wicket/pages/EditUserPage.java b/src/com/gitblit/wicket/pages/EditUserPage.java index 250d1fde..d1faa782 100644 --- a/src/com/gitblit/wicket/pages/EditUserPage.java +++ b/src/com/gitblit/wicket/pages/EditUserPage.java @@ -15,13 +15,18 @@ import org.apache.wicket.model.CompoundPropertyModel; import org.apache.wicket.model.Model;
import org.apache.wicket.model.util.CollectionModel;
import org.apache.wicket.model.util.ListModel;
+import org.eclipse.jetty.http.security.Credential.Crypt;
import org.eclipse.jetty.http.security.Credential.MD5;
+import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.GitBlit;
import com.gitblit.GitBlitException;
+import com.gitblit.Keys;
+import com.gitblit.utils.StringUtils;
import com.gitblit.wicket.AdminPage;
import com.gitblit.wicket.BasePage;
import com.gitblit.wicket.WicketUtils;
+import com.gitblit.wicket.models.RepositoryModel;
import com.gitblit.wicket.models.UserModel;
@AdminPage
@@ -41,7 +46,7 @@ public class EditUserPage extends BasePage { super(params);
isCreate = false;
String name = WicketUtils.getUsername(params);
- UserModel model = GitBlit.self().getUser(name);
+ UserModel model = GitBlit.self().getUserModel(name);
setupPage(model);
}
@@ -51,12 +56,17 @@ public class EditUserPage extends BasePage { } else {
super.setupPage("", getString("gb.edit"));
}
- final Model<String> confirmPassword = new Model<String>();
+ final Model<String> confirmPassword = new Model<String>(StringUtils.isEmpty(userModel.getPassword()) ? "" : userModel.getPassword());
CompoundPropertyModel<UserModel> model = new CompoundPropertyModel<UserModel>(userModel);
- List<String> repos = GitBlit.self().getRepositoryList();
- repos.add(0, "*"); // all repositories wildcard
- final Palette<String> repositories = new Palette<String>("repositories", new ListModel<String>(userModel.getRepositories()), new CollectionModel<String>(repos), new ChoiceRenderer<String>("", ""), 10, false);
+ List<String> repos = new ArrayList<String>();
+ for (String repo : GitBlit.self().getRepositoryList()) {
+ RepositoryModel repositoryModel = GitBlit.self().getRepositoryModel(repo);
+ if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) {
+ repos.add(repo);
+ }
+ }
+ final Palette<String> repositories = new Palette<String>("repositories", new ListModel<String>(userModel.getRepositories()), new CollectionModel<String>(repos), new ChoiceRenderer<String>("", ""), 10, false);
Form<UserModel> form = new Form<UserModel>("editForm", model) {
private static final long serialVersionUID = 1L;
@@ -67,8 +77,20 @@ public class EditUserPage extends BasePage { error("Passwords do not match!");
return;
}
- userModel.setPassword(MD5.digest(userModel.getPassword()));
-
+ String password = userModel.getPassword();
+ if (!password.toUpperCase().startsWith(Crypt.__TYPE) && !password.toUpperCase().startsWith(MD5.__TYPE)) {
+ // This is a plain text password.
+ // Optionally encrypt/obfuscate the password.
+ String type = GitBlit.self().settings().getString(Keys.realm.passwordStorage, "md5");
+ if (type.equalsIgnoreCase("md5")) {
+ // store MD5 checksum of password
+ userModel.setPassword(MD5.digest(userModel.getPassword()));
+ } else if (type.equalsIgnoreCase("crypt")) {
+ // simple unix encryption
+ userModel.setPassword(Crypt.crypt(userModel.getUsername(), userModel.getPassword()));
+ }
+ }
+
Iterator<String> selectedRepositories = repositories.getSelectedChoices();
List<String> repos = new ArrayList<String>();
while (selectedRepositories.hasNext()) {
@@ -82,14 +104,24 @@ public class EditUserPage extends BasePage { return;
}
setRedirect(true);
- setResponsePage(EditUserPage.class);
+ if (isCreate) {
+ // create another user
+ setResponsePage(EditUserPage.class);
+ } else {
+ // back to home
+ setResponsePage(RepositoriesPage.class);
+ }
}
};
// field names reflective match UserModel fields
form.add(new TextField<String>("username").setEnabled(isCreate));
- form.add(new PasswordTextField("password"));
- form.add(new PasswordTextField("confirmPassword", confirmPassword));
+ PasswordTextField passwordField = new PasswordTextField("password");
+ passwordField.setResetPassword(false);
+ form.add(passwordField);
+ PasswordTextField confirmPasswordField = new PasswordTextField("confirmPassword", confirmPassword);
+ confirmPasswordField.setResetPassword(false);
+ form.add(confirmPasswordField);
form.add(new CheckBox("canAdmin"));
form.add(repositories);
add(form);
diff --git a/src/com/gitblit/wicket/pages/RepositoriesPage.html b/src/com/gitblit/wicket/pages/RepositoriesPage.html index 3016f648..c33e530d 100644 --- a/src/com/gitblit/wicket/pages/RepositoriesPage.html +++ b/src/com/gitblit/wicket/pages/RepositoriesPage.html @@ -31,7 +31,7 @@ <td><div class="list" wicket:id="repositoryName">[repository name]</div></td>
<td><div class="list" wicket:id="repositoryDescription">[repository description]</div></td>
<td class="author"><span wicket:id="repositoryOwner">[repository owner]</span></td>
- <td class="icon"><img wicket:id="ticketsIcon" /><img wicket:id="docsIcon" /><img wicket:id="restrictedAccessIcon" /></td>
+ <td class="icon"><img wicket:id="ticketsIcon" /><img wicket:id="docsIcon" /><img wicket:id="accessRestrictionIcon" /></td>
<td><span wicket:id="repositoryLastChange">[last change]</span></td>
<td class="rightAlign"><span wicket:id="repositoryLinks"></span></td>
</tr>
diff --git a/src/com/gitblit/wicket/pages/RepositoriesPage.java b/src/com/gitblit/wicket/pages/RepositoriesPage.java index 45058296..acdc02fa 100644 --- a/src/com/gitblit/wicket/pages/RepositoriesPage.java +++ b/src/com/gitblit/wicket/pages/RepositoriesPage.java @@ -8,6 +8,7 @@ import java.util.Collections; import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
+import java.util.Map;
import org.apache.wicket.Component;
import org.apache.wicket.PageParameters;
@@ -23,6 +24,7 @@ import org.apache.wicket.model.IModel; import org.apache.wicket.model.Model;
import org.apache.wicket.resource.ContextRelativeResource;
+import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
import com.gitblit.utils.MarkdownUtils;
@@ -99,6 +101,7 @@ public class RepositoriesPage extends BasePage { }
add(repositoriesMessage);
+ final Map<AccessRestrictionType, String> accessRestrictionTranslations = getAccessRestrictions();
UserModel user = GitBlitWebSession.get().getUser();
List<RepositoryModel> rows = GitBlit.self().getRepositoryModels(user);
DataProvider dp = new DataProvider(rows);
@@ -130,22 +133,22 @@ public class RepositoriesPage extends BasePage { } else {
item.add(WicketUtils.newBlankImage("docsIcon"));
}
-
+
switch (entry.accessRestriction) {
case NONE:
- item.add(WicketUtils.newBlankImage("restrictedAccessIcon"));
+ item.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
break;
case PUSH:
- item.add(WicketUtils.newImage("restrictedAccessIcon", "lock_go_16x16.png", getString("gb.pushRestricted")));
+ item.add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
break;
case CLONE:
- item.add(WicketUtils.newImage("restrictedAccessIcon", "lock_pull_16x16.png", getString("gb.cloneRestricted")));
+ item.add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
break;
case VIEW:
- item.add(WicketUtils.newImage("restrictedAccessIcon", "shield_16x16.png", getString("gb.viewRestricted")));
+ item.add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", accessRestrictionTranslations.get(entry.accessRestriction)));
break;
default:
- item.add(WicketUtils.newBlankImage("restrictedAccessIcon"));
+ item.add(WicketUtils.newBlankImage("accessRestrictionIcon"));
}
item.add(new Label("repositoryOwner", entry.owner));
diff --git a/src/com/gitblit/wicket/pages/SummaryPage.html b/src/com/gitblit/wicket/pages/SummaryPage.html index 6dbcfa22..35331f56 100644 --- a/src/com/gitblit/wicket/pages/SummaryPage.html +++ b/src/com/gitblit/wicket/pages/SummaryPage.html @@ -20,7 +20,7 @@ <tr><th><wicket:message key="gb.owner">[owner]</wicket:message></th><td><span wicket:id="repositoryOwner">[repository owner]</span></td></tr>
<tr><th><wicket:message key="gb.lastChange">[last change]</wicket:message></th><td><span wicket:id="repositoryLastChange">[repository last change]</span></td></tr>
<tr><th><wicket:message key="gb.stats">[stats]</wicket:message></th><td><span wicket:id="repositoryStats">[repository stats]</span></td></tr>
- <tr><th><wicket:message key="gb.url">[URL]</wicket:message></th><td><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>
+ <tr><th><wicket:message key="gb.url">[URL]</wicket:message></th><td><img style="vertical-align: top; padding-right:5px;" wicket:id="accessRestrictionIcon" /><span wicket:id="repositoryCloneUrl">[repository clone url]</span></td></tr>
</table>
</div>
</div>
diff --git a/src/com/gitblit/wicket/pages/SummaryPage.java b/src/com/gitblit/wicket/pages/SummaryPage.java index c0193dbe..d83f5961 100644 --- a/src/com/gitblit/wicket/pages/SummaryPage.java +++ b/src/com/gitblit/wicket/pages/SummaryPage.java @@ -19,6 +19,7 @@ import org.wicketstuff.googlecharts.LineStyle; import org.wicketstuff.googlecharts.MarkerType;
import org.wicketstuff.googlecharts.ShapeMarker;
+import com.gitblit.Constants.AccessRestrictionType;
import com.gitblit.GitBlit;
import com.gitblit.Keys;
import com.gitblit.utils.JGitUtils;
@@ -66,6 +67,24 @@ public class SummaryPage extends RepositoryPage { } else {
add(new Label("repositoryStats", MessageFormat.format("{0} commits and {1} tags in {2}", metricsTotal.count, metricsTotal.tag, TimeUtils.duration(metricsTotal.duration))));
}
+
+ AccessRestrictionType accessRestriction = getRepositoryModel().accessRestriction;
+ switch (accessRestriction) {
+ case NONE:
+ add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
+ break;
+ case PUSH:
+ add(WicketUtils.newImage("accessRestrictionIcon", "lock_go_16x16.png", getAccessRestrictions().get(accessRestriction)));
+ break;
+ case CLONE:
+ add(WicketUtils.newImage("accessRestrictionIcon", "lock_pull_16x16.png", getAccessRestrictions().get(accessRestriction)));
+ break;
+ case VIEW:
+ add(WicketUtils.newImage("accessRestrictionIcon", "shield_16x16.png", getAccessRestrictions().get(accessRestriction)));
+ break;
+ default:
+ add(WicketUtils.newClearPixel("accessRestrictionIcon").setVisible(false));
+ }
add(new Label("repositoryCloneUrl", GitBlit.self().getCloneUrl(repositoryName)));
add(new LogPanel("commitsPanel", repositoryName, null, r, numberCommits, 0));
diff --git a/users.properties b/users.properties index 0b22d827..920f3233 100644 --- a/users.properties +++ b/users.properties @@ -1,3 +1,2 @@ -#Wed May 11 21:30:28 EDT 2011
+# Git:Blit realm file format: username=password,\#permission,repository1,repository2...
admin=admin,\#admin
-test=test
|