From f988253399ee475aa4f4e60adb95a220f8f88d21 Mon Sep 17 00:00:00 2001 From: James Moger Date: Thu, 12 May 2011 17:33:31 -0400 Subject: Moved distribution files. Revised build script. Security revisions. --- src/com/gitblit/Constants.java | 20 +- src/com/gitblit/GitBlit.java | 16 +- src/com/gitblit/GitBlitServer.java | 2 +- src/com/gitblit/ILoginService.java | 12 + src/com/gitblit/JettyLoginService.java | 313 ++++++++++++++++++--- src/com/gitblit/wicket/BasePage.java | 24 ++ src/com/gitblit/wicket/GitBlitWebApp.properties | 15 +- .../gitblit/wicket/pages/EditRepositoryPage.html | 9 +- .../gitblit/wicket/pages/EditRepositoryPage.java | 84 +++++- src/com/gitblit/wicket/pages/EditUserPage.html | 4 +- src/com/gitblit/wicket/pages/EditUserPage.java | 52 +++- src/com/gitblit/wicket/pages/RepositoriesPage.html | 2 +- src/com/gitblit/wicket/pages/RepositoriesPage.java | 15 +- src/com/gitblit/wicket/pages/SummaryPage.html | 2 +- src/com/gitblit/wicket/pages/SummaryPage.java | 19 ++ 15 files changed, 503 insertions(+), 86 deletions(-) (limited to 'src/com') 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 getAllUsernames() { + return loginService.getAllUsernames(); + } - public UserModel getUser(String username) { + public UserModel getUserModel(String username) { UserModel user = loginService.getUserModel(username); return user; } + + public List getRepositoryUsers(RepositoryModel repository) { + return loginService.getUsernamesForRole(repository.name); + } + + public boolean setRepositoryUsers(RepositoryModel repository, List 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 getAllUsernames(); + + List getUsernamesForRole(String role); + + boolean setUsernamesForRole(String role, List 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 roles = new ArrayList(); - - // Repositories - roles.addAll(model.getRepositories()); + Properties allUsers = readRealmFile(); + ArrayList roles = new ArrayList(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 getAllUsernames() { + List list = new ArrayList(); + list.addAll(_users.keySet()); + return list; + } + + @Override + public List getUsernamesForRole(String role) { + List list = new ArrayList(); + 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 usernames) { + try { + Set specifiedUsers = new HashSet(usernames); + Set needsAddRole = new HashSet(specifiedUsers); + Set needsRemoveRole = new HashSet(); + + // 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 revisedRoles = new ArrayList(); + // 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 needsRenameRole = new HashSet(); + + // 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 revisedRoles = new ArrayList(); + 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 needsDeleteRole = new HashSet(); + + // 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 revisedRoles = new ArrayList(); + // 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 entry : properties.entrySet()) { + for (Map.Entry 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 getAccessRestrictions() { + Map map = new LinkedHashMap(); + 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 @@ -  distributed Ticgit issues -  enumerates Markdown documentation in repository -  show remote branches +   +   +   + 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 repositoryUsers = new ArrayList(); 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 usersPalette = new Palette("users", new ListModel(repositoryUsers), new CollectionModel(GitBlit.self().getAllUsernames()), new ChoiceRenderer("", ""), 10, false); CompoundPropertyModel model = new CompoundPropertyModel(repositoryModel); Form form = new Form("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 users = usersPalette.getSelectedChoices(); + List repositoryUsers = new ArrayList(); + 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("name").setEnabled(isCreate)); form.add(new TextField("description")); form.add(new TextField("owner")); - form.add(new DropDownChoice("accessRestriction", Arrays.asList(AccessRestrictionType.values()))); + form.add(new DropDownChoice("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 { + + private static final long serialVersionUID = 1L; + + private final Map 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 @@ -  can administer Git:Blit server - +   + 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 confirmPassword = new Model(); + final Model confirmPassword = new Model(StringUtils.isEmpty(userModel.getPassword()) ? "" : userModel.getPassword()); CompoundPropertyModel model = new CompoundPropertyModel(userModel); - List repos = GitBlit.self().getRepositoryList(); - repos.add(0, "*"); // all repositories wildcard - final Palette repositories = new Palette("repositories", new ListModel(userModel.getRepositories()), new CollectionModel(repos), new ChoiceRenderer("", ""), 10, false); + List repos = new ArrayList(); + for (String repo : GitBlit.self().getRepositoryList()) { + RepositoryModel repositoryModel = GitBlit.self().getRepositoryModel(repo); + if (repositoryModel.accessRestriction.exceeds(AccessRestrictionType.NONE)) { + repos.add(repo); + } + } + final Palette repositories = new Palette("repositories", new ListModel(userModel.getRepositories()), new CollectionModel(repos), new ChoiceRenderer("", ""), 10, false); Form form = new Form("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 selectedRepositories = repositories.getSelectedChoices(); List repos = new ArrayList(); 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("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 @@
[repository name]
[repository description]
[repository owner] - + [last change] 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 accessRestrictionTranslations = getAccessRestrictions(); UserModel user = GitBlitWebSession.get().getUser(); List 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 @@ [owner][repository owner] [last change][repository last change] [stats][repository stats] - [URL][repository clone url] + [URL][repository clone url] 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)); -- cgit v1.2.3