From dbc0831e24e391a78e490b892e958a05d7e95116 Mon Sep 17 00:00:00 2001
From: James Moger <james.moger@gitblit.com>
Date: Thu, 19 May 2011 17:18:29 -0400
Subject: [PATCH] Documentation tweak.
---
src/com/gitblit/JettyLoginService.java | 332 +++++++++++++++++++++++++++++++++++++++++++++++--------
1 files changed, 284 insertions(+), 48 deletions(-)
diff --git a/src/com/gitblit/JettyLoginService.java b/src/com/gitblit/JettyLoginService.java
index ddd3722..c191f0f 100644
--- a/src/com/gitblit/JettyLoginService.java
+++ b/src/com/gitblit/JettyLoginService.java
@@ -5,9 +5,13 @@
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,11 +20,15 @@
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.User;
+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;
@@ -31,12 +39,12 @@
}
@Override
- public User authenticate(String username, char[] password) {
+ public UserModel authenticate(String username, char[] password) {
UserIdentity identity = login(username, new String(password));
if (identity == null || identity.equals(UserIdentity.UNAUTHENTICATED_IDENTITY)) {
return null;
}
- User user = new User(username);
+ UserModel user = new UserModel(username);
user.setCookie(StringUtils.getSHA1((Constants.NAME + username + new String(password))));
user.canAdmin(identity.isUserInRole(Constants.ADMIN_ROLE, null));
@@ -44,8 +52,9 @@
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);
}
}
}
@@ -53,15 +62,18 @@
}
@Override
- public User authenticate(char[] cookie) {
+ public UserModel authenticate(char[] cookie) {
// TODO cookie login
return null;
}
@Override
- public User getUserModel(String username) {
- User model = new User(username);
+ public UserModel getUserModel(String username) {
UserIdentity identity = _users.get(username);
+ if (identity == null) {
+ return null;
+ }
+ UserModel model = new UserModel(username);
Subject subject = identity.getSubject();
for (Principal principal : subject.getPrincipals()) {
if (principal instanceof RolePrincipal) {
@@ -75,25 +87,29 @@
}
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(User model) {
+ 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,50 +125,273 @@
}
// 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;
}
@Override
- public boolean deleteUserModel(User model) {
+ 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!");
+ }
}
/* ------------------------------------------------------------ */
@@ -163,13 +402,10 @@
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;
--
Gitblit v1.9.1