diff options
Diffstat (limited to 'src/com')
-rw-r--r-- | src/com/gitblit/Constants.java | 20 | ||||
-rw-r--r-- | src/com/gitblit/GitBlit.java | 16 | ||||
-rw-r--r-- | src/com/gitblit/GitBlitServer.java | 2 | ||||
-rw-r--r-- | src/com/gitblit/ILoginService.java | 12 | ||||
-rw-r--r-- | src/com/gitblit/JettyLoginService.java | 313 | ||||
-rw-r--r-- | src/com/gitblit/wicket/BasePage.java | 24 | ||||
-rw-r--r-- | src/com/gitblit/wicket/GitBlitWebApp.properties | 15 | ||||
-rw-r--r-- | src/com/gitblit/wicket/pages/EditRepositoryPage.html | 9 | ||||
-rw-r--r-- | src/com/gitblit/wicket/pages/EditRepositoryPage.java | 84 | ||||
-rw-r--r-- | src/com/gitblit/wicket/pages/EditUserPage.html | 4 | ||||
-rw-r--r-- | src/com/gitblit/wicket/pages/EditUserPage.java | 52 | ||||
-rw-r--r-- | src/com/gitblit/wicket/pages/RepositoriesPage.html | 2 | ||||
-rw-r--r-- | src/com/gitblit/wicket/pages/RepositoriesPage.java | 15 | ||||
-rw-r--r-- | src/com/gitblit/wicket/pages/SummaryPage.html | 2 | ||||
-rw-r--r-- | src/com/gitblit/wicket/pages/SummaryPage.java | 19 |
15 files changed, 503 insertions, 86 deletions
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));
|