+++ /dev/null
-/*\r
- * Copyright 2011 gitblit.com.\r
- *\r
- * Licensed under the Apache License, Version 2.0 (the "License");\r
- * you may not use this file except in compliance with the License.\r
- * You may obtain a copy of the License at\r
- *\r
- * http://www.apache.org/licenses/LICENSE-2.0\r
- *\r
- * Unless required by applicable law or agreed to in writing, software\r
- * distributed under the License is distributed on an "AS IS" BASIS,\r
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
- * See the License for the specific language governing permissions and\r
- * limitations under the License.\r
- */\r
-package com.gitblit;\r
-\r
-import java.io.File;\r
-import java.io.FileWriter;\r
-import java.io.IOException;\r
-import java.text.MessageFormat;\r
-import java.util.ArrayList;\r
-import java.util.Collection;\r
-import java.util.Collections;\r
-import java.util.HashSet;\r
-import java.util.List;\r
-import java.util.Map;\r
-import java.util.Properties;\r
-import java.util.Set;\r
-import java.util.concurrent.ConcurrentHashMap;\r
-\r
-import org.slf4j.Logger;\r
-import org.slf4j.LoggerFactory;\r
-\r
-import com.gitblit.Constants.AccessPermission;\r
-import com.gitblit.models.TeamModel;\r
-import com.gitblit.models.UserModel;\r
-import com.gitblit.utils.ArrayUtils;\r
-import com.gitblit.utils.DeepCopier;\r
-import com.gitblit.utils.StringUtils;\r
-\r
-/**\r
- * FileUserService is Gitblit's original default user service implementation.\r
- * \r
- * Users and their repository memberships are stored in a simple properties file\r
- * which is cached and dynamically reloaded when modified.\r
- * \r
- * This class was deprecated in Gitblit 0.8.0 in favor of ConfigUserService\r
- * which is still a human-readable, editable, plain-text file but it is more\r
- * flexible for storing additional fields.\r
- * \r
- * @author James Moger\r
- * \r
- */\r
-@Deprecated\r
-public class FileUserService extends FileSettings implements IUserService {\r
-\r
- private final Logger logger = LoggerFactory.getLogger(FileUserService.class);\r
-\r
- private final Map<String, String> cookies = new ConcurrentHashMap<String, String>();\r
-\r
- private final Map<String, TeamModel> teams = new ConcurrentHashMap<String, TeamModel>();\r
-\r
- public FileUserService(File realmFile) {\r
- super(realmFile.getAbsolutePath());\r
- }\r
-\r
- /**\r
- * Setup the user service.\r
- * \r
- * @param settings\r
- * @since 0.7.0\r
- */\r
- @Override\r
- public void setup(IStoredSettings settings) {\r
- }\r
-\r
- /**\r
- * Does the user service support changes to credentials?\r
- * \r
- * @return true or false\r
- * @since 1.0.0\r
- */\r
- @Override\r
- public boolean supportsCredentialChanges() {\r
- return true;\r
- }\r
-\r
- /**\r
- * Does the user service support changes to user display name?\r
- * \r
- * @return true or false\r
- * @since 1.0.0\r
- */\r
- @Override\r
- public boolean supportsDisplayNameChanges() {\r
- return false;\r
- }\r
-\r
- /**\r
- * Does the user service support changes to user email address?\r
- * \r
- * @return true or false\r
- * @since 1.0.0\r
- */\r
- @Override\r
- public boolean supportsEmailAddressChanges() {\r
- return false;\r
- }\r
-\r
- /**\r
- * Does the user service support changes to team memberships?\r
- * \r
- * @return true or false\r
- * @since 1.0.0\r
- */ \r
- public boolean supportsTeamMembershipChanges() {\r
- return true;\r
- }\r
-\r
- /**\r
- * Does the user service support cookie authentication?\r
- * \r
- * @return true or false\r
- */\r
- @Override\r
- public boolean supportsCookies() {\r
- return true;\r
- }\r
-\r
- /**\r
- * Returns the cookie value for the specified user.\r
- * \r
- * @param model\r
- * @return cookie value\r
- */\r
- @Override\r
- public String getCookie(UserModel model) {\r
- if (!StringUtils.isEmpty(model.cookie)) {\r
- return model.cookie;\r
- }\r
- Properties allUsers = super.read();\r
- String value = allUsers.getProperty(model.username);\r
- String[] roles = value.split(",");\r
- String password = roles[0];\r
- String cookie = StringUtils.getSHA1(model.username + password);\r
- return cookie;\r
- }\r
-\r
- /**\r
- * Authenticate a user based on their cookie.\r
- * \r
- * @param cookie\r
- * @return a user object or null\r
- */\r
- @Override\r
- public UserModel authenticate(char[] cookie) {\r
- String hash = new String(cookie);\r
- if (StringUtils.isEmpty(hash)) {\r
- return null;\r
- }\r
- read();\r
- UserModel model = null;\r
- if (cookies.containsKey(hash)) {\r
- String username = cookies.get(hash);\r
- model = getUserModel(username);\r
- }\r
- return model;\r
- }\r
-\r
- /**\r
- * Authenticate a user based on a username and password.\r
- * \r
- * @param username\r
- * @param password\r
- * @return a user object or null\r
- */\r
- @Override\r
- public UserModel authenticate(String username, char[] password) {\r
- Properties allUsers = read();\r
- String userInfo = allUsers.getProperty(username);\r
- if (StringUtils.isEmpty(userInfo)) {\r
- return null;\r
- }\r
- UserModel returnedUser = null;\r
- UserModel user = getUserModel(username);\r
- if (user.password.startsWith(StringUtils.MD5_TYPE)) {\r
- // password digest\r
- String md5 = StringUtils.MD5_TYPE + StringUtils.getMD5(new String(password));\r
- if (user.password.equalsIgnoreCase(md5)) {\r
- returnedUser = user;\r
- }\r
- } else if (user.password.startsWith(StringUtils.COMBINED_MD5_TYPE)) {\r
- // username+password digest\r
- String md5 = StringUtils.COMBINED_MD5_TYPE\r
- + StringUtils.getMD5(username.toLowerCase() + new String(password));\r
- if (user.password.equalsIgnoreCase(md5)) {\r
- returnedUser = user;\r
- }\r
- } else if (user.password.equals(new String(password))) {\r
- // plain-text password\r
- returnedUser = user;\r
- }\r
- return returnedUser;\r
- }\r
-\r
- /**\r
- * Logout a user.\r
- * \r
- * @param user\r
- */\r
- @Override\r
- public void logout(UserModel user) { \r
- }\r
-\r
- /**\r
- * Retrieve the user object for the specified username.\r
- * \r
- * @param username\r
- * @return a user object or null\r
- */\r
- @Override\r
- public UserModel getUserModel(String username) {\r
- Properties allUsers = read();\r
- String userInfo = allUsers.getProperty(username.toLowerCase());\r
- if (userInfo == null) {\r
- return null;\r
- }\r
- UserModel model = new UserModel(username.toLowerCase());\r
- String[] userValues = userInfo.split(",");\r
- model.password = userValues[0];\r
- for (int i = 1; i < userValues.length; i++) {\r
- String role = userValues[i];\r
- switch (role.charAt(0)) {\r
- case '#':\r
- // Permissions\r
- if (role.equalsIgnoreCase(Constants.ADMIN_ROLE)) {\r
- model.canAdmin = true;\r
- } else if (role.equalsIgnoreCase(Constants.FORK_ROLE)) {\r
- model.canFork = true;\r
- } else if (role.equalsIgnoreCase(Constants.CREATE_ROLE)) {\r
- model.canCreate = true;\r
- } else if (role.equalsIgnoreCase(Constants.NOT_FEDERATED_ROLE)) {\r
- model.excludeFromFederation = true;\r
- }\r
- break;\r
- default:\r
- model.addRepositoryPermission(role);\r
- }\r
- }\r
- // set the teams for the user\r
- for (TeamModel team : teams.values()) {\r
- if (team.hasUser(username)) {\r
- model.teams.add(DeepCopier.copy(team));\r
- }\r
- }\r
- return model;\r
- }\r
-\r
- /**\r
- * Updates/writes a complete user object.\r
- * \r
- * @param model\r
- * @return true if update is successful\r
- */\r
- @Override\r
- public boolean updateUserModel(UserModel model) {\r
- return updateUserModel(model.username, model);\r
- }\r
-\r
- /**\r
- * Updates/writes all specified user objects.\r
- * \r
- * @param models a list of user models\r
- * @return true if update is successful\r
- * @since 1.2.0\r
- */\r
- @Override\r
- public boolean updateUserModels(Collection<UserModel> models) {\r
- try { \r
- Properties allUsers = read();\r
- for (UserModel model : models) {\r
- updateUserCache(allUsers, model.username, model);\r
- }\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to update {0} user models!", models.size()),\r
- t);\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Updates/writes and replaces a complete user object keyed by username.\r
- * This method allows for renaming a user.\r
- * \r
- * @param username\r
- * the old username\r
- * @param model\r
- * the user object to use for username\r
- * @return true if update is successful\r
- */\r
- @Override\r
- public boolean updateUserModel(String username, UserModel model) {\r
- try { \r
- Properties allUsers = read();\r
- updateUserCache(allUsers, username, model);\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to update user model {0}!", model.username),\r
- t);\r
- }\r
- return false;\r
- }\r
- \r
- /**\r
- * Updates/writes and replaces a complete user object keyed by username.\r
- * This method allows for renaming a user.\r
- * \r
- * @param username\r
- * the old username\r
- * @param model\r
- * the user object to use for username\r
- * @return true if update is successful\r
- */\r
- private boolean updateUserCache(Properties allUsers, String username, UserModel model) {\r
- try { \r
- UserModel oldUser = getUserModel(username);\r
- List<String> roles;\r
- if (model.permissions == null) {\r
- roles = new ArrayList<String>();\r
- } else {\r
- // discrete repository permissions\r
- roles = new ArrayList<String>();\r
- for (Map.Entry<String, AccessPermission> entry : model.permissions.entrySet()) {\r
- if (entry.getValue().exceeds(AccessPermission.NONE)) {\r
- // code:repository (e.g. RW+:~james/myrepo.git\r
- roles.add(entry.getValue().asRole(entry.getKey()));\r
- }\r
- }\r
- }\r
-\r
- // Permissions\r
- if (model.canAdmin) {\r
- roles.add(Constants.ADMIN_ROLE);\r
- }\r
- if (model.canFork) {\r
- roles.add(Constants.FORK_ROLE);\r
- }\r
- if (model.canCreate) {\r
- roles.add(Constants.CREATE_ROLE);\r
- }\r
- if (model.excludeFromFederation) {\r
- roles.add(Constants.NOT_FEDERATED_ROLE);\r
- }\r
-\r
- StringBuilder sb = new StringBuilder();\r
- if (!StringUtils.isEmpty(model.password)) {\r
- sb.append(model.password);\r
- }\r
- sb.append(',');\r
- for (String role : roles) {\r
- sb.append(role);\r
- sb.append(',');\r
- }\r
- // trim trailing comma\r
- sb.setLength(sb.length() - 1);\r
- allUsers.remove(username.toLowerCase());\r
- allUsers.put(model.username.toLowerCase(), sb.toString());\r
-\r
- // null check on "final" teams because JSON-sourced UserModel\r
- // can have a null teams object\r
- if (model.teams != null) {\r
- // update team cache\r
- for (TeamModel team : model.teams) {\r
- TeamModel t = getTeamModel(team.name);\r
- if (t == null) {\r
- // new team\r
- t = team;\r
- }\r
- t.removeUser(username);\r
- t.addUser(model.username);\r
- updateTeamCache(allUsers, t.name, t);\r
- }\r
-\r
- // check for implicit team removal\r
- if (oldUser != null) {\r
- for (TeamModel team : oldUser.teams) {\r
- if (!model.isTeamMember(team.name)) {\r
- team.removeUser(username);\r
- updateTeamCache(allUsers, team.name, team);\r
- }\r
- }\r
- }\r
- }\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to update user model {0}!", model.username),\r
- t);\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Deletes the user object from the user service.\r
- * \r
- * @param model\r
- * @return true if successful\r
- */\r
- @Override\r
- public boolean deleteUserModel(UserModel model) {\r
- return deleteUser(model.username);\r
- }\r
-\r
- /**\r
- * Delete the user object with the specified username\r
- * \r
- * @param username\r
- * @return true if successful\r
- */\r
- @Override\r
- public boolean deleteUser(String username) {\r
- try {\r
- // Read realm file\r
- Properties allUsers = read();\r
- UserModel user = getUserModel(username);\r
- allUsers.remove(username);\r
- for (TeamModel team : user.teams) {\r
- TeamModel t = getTeamModel(team.name);\r
- if (t == null) {\r
- // new team\r
- t = team;\r
- }\r
- t.removeUser(username);\r
- updateTeamCache(allUsers, t.name, t);\r
- }\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to delete user {0}!", username), t);\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Returns the list of all users available to the login service.\r
- * \r
- * @return list of all usernames\r
- */\r
- @Override\r
- public List<String> getAllUsernames() {\r
- Properties allUsers = read();\r
- List<String> list = new ArrayList<String>();\r
- for (String user : allUsers.stringPropertyNames()) {\r
- if (user.charAt(0) == '@') {\r
- // skip team user definitions\r
- continue;\r
- }\r
- list.add(user);\r
- }\r
- Collections.sort(list);\r
- return list;\r
- }\r
-\r
- /**\r
- * Returns the list of all users available to the login service.\r
- * \r
- * @return list of all usernames\r
- */\r
- @Override\r
- public List<UserModel> getAllUsers() {\r
- read();\r
- List<UserModel> list = new ArrayList<UserModel>();\r
- for (String username : getAllUsernames()) {\r
- list.add(getUserModel(username));\r
- }\r
- Collections.sort(list);\r
- return list;\r
- }\r
-\r
- /**\r
- * Returns the list of all users who are allowed to bypass the access\r
- * restriction placed on the specified repository.\r
- * \r
- * @param role\r
- * the repository name\r
- * @return list of all usernames that can bypass the access restriction\r
- */\r
- @Override\r
- public List<String> getUsernamesForRepositoryRole(String role) {\r
- List<String> list = new ArrayList<String>();\r
- try {\r
- Properties allUsers = read();\r
- for (String username : allUsers.stringPropertyNames()) {\r
- if (username.charAt(0) == '@') {\r
- continue;\r
- }\r
- String value = allUsers.getProperty(username);\r
- String[] values = value.split(",");\r
- // skip first value (password)\r
- for (int i = 1; i < values.length; i++) {\r
- String r = values[i];\r
- if (r.equalsIgnoreCase(role)) {\r
- list.add(username);\r
- break;\r
- }\r
- }\r
- }\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to get usernames for role {0}!", role), t);\r
- }\r
- Collections.sort(list);\r
- return list;\r
- }\r
-\r
- /**\r
- * Sets the list of all users who are allowed to bypass the access\r
- * restriction placed on the specified repository.\r
- * \r
- * @param role\r
- * the repository name\r
- * @param usernames\r
- * @return true if successful\r
- */\r
- @Override\r
- public boolean setUsernamesForRepositoryRole(String role, List<String> usernames) {\r
- try {\r
- Set<String> specifiedUsers = new HashSet<String>(usernames);\r
- Set<String> needsAddRole = new HashSet<String>(specifiedUsers);\r
- Set<String> needsRemoveRole = new HashSet<String>();\r
-\r
- // identify users which require add and remove role\r
- Properties allUsers = read();\r
- for (String username : allUsers.stringPropertyNames()) {\r
- String value = allUsers.getProperty(username);\r
- String[] values = value.split(",");\r
- // skip first value (password)\r
- for (int i = 1; i < values.length; i++) {\r
- String r = values[i];\r
- if (r.equalsIgnoreCase(role)) {\r
- // user has role, check against revised user list\r
- if (specifiedUsers.contains(username)) {\r
- needsAddRole.remove(username);\r
- } else {\r
- // remove role from user\r
- needsRemoveRole.add(username);\r
- }\r
- break;\r
- }\r
- }\r
- }\r
-\r
- // add roles to users\r
- for (String user : needsAddRole) {\r
- String userValues = allUsers.getProperty(user);\r
- userValues += "," + role;\r
- allUsers.put(user, userValues);\r
- }\r
-\r
- // remove role from user\r
- for (String user : needsRemoveRole) {\r
- String[] values = allUsers.getProperty(user).split(",");\r
- String password = values[0];\r
- StringBuilder sb = new StringBuilder();\r
- sb.append(password);\r
- sb.append(',');\r
-\r
- // skip first value (password)\r
- for (int i = 1; i < values.length; i++) {\r
- String value = values[i];\r
- if (!value.equalsIgnoreCase(role)) {\r
- sb.append(value);\r
- sb.append(',');\r
- }\r
- }\r
- sb.setLength(sb.length() - 1);\r
-\r
- // update properties\r
- allUsers.put(user, sb.toString());\r
- }\r
-\r
- // persist changes\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to set usernames for role {0}!", role), t);\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Renames a repository role.\r
- * \r
- * @param oldRole\r
- * @param newRole\r
- * @return true if successful\r
- */\r
- @Override\r
- public boolean renameRepositoryRole(String oldRole, String newRole) {\r
- try {\r
- Properties allUsers = read();\r
- Set<String> needsRenameRole = new HashSet<String>();\r
-\r
- // identify users which require role rename\r
- for (String username : allUsers.stringPropertyNames()) {\r
- String value = allUsers.getProperty(username);\r
- String[] roles = value.split(",");\r
- // skip first value (password)\r
- for (int i = 1; i < roles.length; i++) {\r
- String repository = AccessPermission.repositoryFromRole(roles[i]);\r
- if (repository.equalsIgnoreCase(oldRole)) {\r
- needsRenameRole.add(username);\r
- break;\r
- }\r
- }\r
- }\r
-\r
- // rename role for identified users\r
- for (String user : needsRenameRole) {\r
- String userValues = allUsers.getProperty(user);\r
- String[] values = userValues.split(",");\r
- String password = values[0];\r
- StringBuilder sb = new StringBuilder();\r
- sb.append(password);\r
- sb.append(',');\r
- sb.append(newRole);\r
- sb.append(',');\r
-\r
- // skip first value (password)\r
- for (int i = 1; i < values.length; i++) {\r
- String repository = AccessPermission.repositoryFromRole(values[i]);\r
- if (repository.equalsIgnoreCase(oldRole)) {\r
- AccessPermission permission = AccessPermission.permissionFromRole(values[i]);\r
- sb.append(permission.asRole(newRole));\r
- sb.append(',');\r
- } else {\r
- sb.append(values[i]);\r
- sb.append(',');\r
- }\r
- }\r
- sb.setLength(sb.length() - 1);\r
-\r
- // update properties\r
- allUsers.put(user, sb.toString());\r
- }\r
-\r
- // persist changes\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(\r
- MessageFormat.format("Failed to rename role {0} to {1}!", oldRole, newRole), t);\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Removes a repository role from all users.\r
- * \r
- * @param role\r
- * @return true if successful\r
- */\r
- @Override\r
- public boolean deleteRepositoryRole(String role) {\r
- try {\r
- Properties allUsers = read();\r
- Set<String> needsDeleteRole = new HashSet<String>();\r
-\r
- // identify users which require role rename\r
- for (String username : allUsers.stringPropertyNames()) {\r
- String value = allUsers.getProperty(username);\r
- String[] roles = value.split(",");\r
- // skip first value (password)\r
- for (int i = 1; i < roles.length; i++) { \r
- String repository = AccessPermission.repositoryFromRole(roles[i]);\r
- if (repository.equalsIgnoreCase(role)) {\r
- needsDeleteRole.add(username);\r
- break;\r
- }\r
- }\r
- }\r
-\r
- // delete role for identified users\r
- for (String user : needsDeleteRole) {\r
- String userValues = allUsers.getProperty(user);\r
- String[] values = userValues.split(",");\r
- String password = values[0];\r
- StringBuilder sb = new StringBuilder();\r
- sb.append(password);\r
- sb.append(',');\r
- // skip first value (password)\r
- for (int i = 1; i < values.length; i++) { \r
- String repository = AccessPermission.repositoryFromRole(values[i]);\r
- if (!repository.equalsIgnoreCase(role)) {\r
- sb.append(values[i]);\r
- sb.append(',');\r
- }\r
- }\r
- sb.setLength(sb.length() - 1);\r
-\r
- // update properties\r
- allUsers.put(user, sb.toString());\r
- }\r
-\r
- // persist changes\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to delete role {0}!", role), t);\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Writes the properties file.\r
- * \r
- * @param properties\r
- * @throws IOException\r
- */\r
- private void write(Properties properties) throws IOException {\r
- // Write a temporary copy of the users file\r
- File realmFileCopy = new File(propertiesFile.getAbsolutePath() + ".tmp");\r
- FileWriter writer = new FileWriter(realmFileCopy);\r
- properties\r
- .store(writer,\r
- " Gitblit realm file format:\n username=password,\\#permission,repository1,repository2...\n @teamname=!username1,!username2,!username3,repository1,repository2...");\r
- writer.close();\r
- // If the write is successful, delete the current file and rename\r
- // the temporary copy to the original filename.\r
- if (realmFileCopy.exists() && realmFileCopy.length() > 0) {\r
- if (propertiesFile.exists()) {\r
- if (!propertiesFile.delete()) {\r
- throw new IOException(MessageFormat.format("Failed to delete {0}!",\r
- propertiesFile.getAbsolutePath()));\r
- }\r
- }\r
- if (!realmFileCopy.renameTo(propertiesFile)) {\r
- throw new IOException(MessageFormat.format("Failed to rename {0} to {1}!",\r
- realmFileCopy.getAbsolutePath(), propertiesFile.getAbsolutePath()));\r
- }\r
- } else {\r
- throw new IOException(MessageFormat.format("Failed to save {0}!",\r
- realmFileCopy.getAbsolutePath()));\r
- }\r
- }\r
-\r
- /**\r
- * Reads the properties file and rebuilds the in-memory cookie lookup table.\r
- */\r
- @Override\r
- protected synchronized Properties read() {\r
- long lastRead = lastModified();\r
- boolean reload = forceReload();\r
- Properties allUsers = super.read();\r
- if (reload || (lastRead != lastModified())) {\r
- // reload hash cache\r
- cookies.clear();\r
- teams.clear();\r
-\r
- for (String username : allUsers.stringPropertyNames()) {\r
- String value = allUsers.getProperty(username);\r
- String[] roles = value.split(",");\r
- if (username.charAt(0) == '@') {\r
- // team definition\r
- TeamModel team = new TeamModel(username.substring(1));\r
- List<String> repositories = new ArrayList<String>();\r
- List<String> users = new ArrayList<String>();\r
- List<String> mailingLists = new ArrayList<String>();\r
- List<String> preReceive = new ArrayList<String>();\r
- List<String> postReceive = new ArrayList<String>();\r
- for (String role : roles) {\r
- if (role.charAt(0) == '!') {\r
- users.add(role.substring(1));\r
- } else if (role.charAt(0) == '&') {\r
- mailingLists.add(role.substring(1));\r
- } else if (role.charAt(0) == '^') {\r
- preReceive.add(role.substring(1));\r
- } else if (role.charAt(0) == '%') {\r
- postReceive.add(role.substring(1));\r
- } else {\r
- switch (role.charAt(0)) {\r
- case '#':\r
- // Permissions\r
- if (role.equalsIgnoreCase(Constants.ADMIN_ROLE)) {\r
- team.canAdmin = true;\r
- } else if (role.equalsIgnoreCase(Constants.FORK_ROLE)) {\r
- team.canFork = true;\r
- } else if (role.equalsIgnoreCase(Constants.CREATE_ROLE)) {\r
- team.canCreate = true;\r
- }\r
- break;\r
- default:\r
- repositories.add(role);\r
- }\r
- repositories.add(role);\r
- }\r
- }\r
- if (!team.canAdmin) {\r
- // only read permissions for non-admin teams\r
- team.addRepositoryPermissions(repositories);\r
- }\r
- team.addUsers(users);\r
- team.addMailingLists(mailingLists);\r
- team.preReceiveScripts.addAll(preReceive);\r
- team.postReceiveScripts.addAll(postReceive);\r
- teams.put(team.name.toLowerCase(), team);\r
- } else {\r
- // user definition\r
- String password = roles[0];\r
- cookies.put(StringUtils.getSHA1(username.toLowerCase() + password), username.toLowerCase());\r
- }\r
- }\r
- }\r
- return allUsers;\r
- }\r
-\r
- @Override\r
- public String toString() {\r
- return getClass().getSimpleName() + "(" + propertiesFile.getAbsolutePath() + ")";\r
- }\r
-\r
- /**\r
- * Returns the list of all teams available to the login service.\r
- * \r
- * @return list of all teams\r
- * @since 0.8.0\r
- */\r
- @Override\r
- public List<String> getAllTeamNames() {\r
- List<String> list = new ArrayList<String>(teams.keySet());\r
- Collections.sort(list);\r
- return list;\r
- }\r
-\r
- /**\r
- * Returns the list of all teams available to the login service.\r
- * \r
- * @return list of all teams\r
- * @since 0.8.0\r
- */\r
- @Override\r
- public List<TeamModel> getAllTeams() {\r
- List<TeamModel> list = new ArrayList<TeamModel>(teams.values());\r
- list = DeepCopier.copy(list);\r
- Collections.sort(list);\r
- return list;\r
- }\r
-\r
- /**\r
- * Returns the list of all teams who are allowed to bypass the access\r
- * restriction placed on the specified repository.\r
- * \r
- * @param role\r
- * the repository name\r
- * @return list of all teamnames that can bypass the access restriction\r
- */\r
- @Override\r
- public List<String> getTeamnamesForRepositoryRole(String role) {\r
- List<String> list = new ArrayList<String>();\r
- try {\r
- Properties allUsers = read();\r
- for (String team : allUsers.stringPropertyNames()) {\r
- if (team.charAt(0) != '@') {\r
- // skip users\r
- continue;\r
- }\r
- String value = allUsers.getProperty(team);\r
- String[] values = value.split(",");\r
- for (int i = 0; i < values.length; i++) {\r
- String r = values[i];\r
- if (r.equalsIgnoreCase(role)) {\r
- // strip leading @\r
- list.add(team.substring(1));\r
- break;\r
- }\r
- }\r
- }\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to get teamnames for role {0}!", role), t);\r
- }\r
- Collections.sort(list);\r
- return list;\r
- }\r
-\r
- /**\r
- * Sets the list of all teams who are allowed to bypass the access\r
- * restriction placed on the specified repository.\r
- * \r
- * @param role\r
- * the repository name\r
- * @param teamnames\r
- * @return true if successful\r
- */\r
- @Override\r
- public boolean setTeamnamesForRepositoryRole(String role, List<String> teamnames) {\r
- try {\r
- Set<String> specifiedTeams = new HashSet<String>(teamnames);\r
- Set<String> needsAddRole = new HashSet<String>(specifiedTeams);\r
- Set<String> needsRemoveRole = new HashSet<String>();\r
-\r
- // identify teams which require add and remove role\r
- Properties allUsers = read();\r
- for (String team : allUsers.stringPropertyNames()) {\r
- if (team.charAt(0) != '@') {\r
- // skip users\r
- continue;\r
- }\r
- String name = team.substring(1);\r
- String value = allUsers.getProperty(team);\r
- String[] values = value.split(",");\r
- for (int i = 0; i < values.length; i++) {\r
- String r = values[i];\r
- if (r.equalsIgnoreCase(role)) {\r
- // team has role, check against revised team list\r
- if (specifiedTeams.contains(name)) {\r
- needsAddRole.remove(name);\r
- } else {\r
- // remove role from team\r
- needsRemoveRole.add(name);\r
- }\r
- break;\r
- }\r
- }\r
- }\r
-\r
- // add roles to teams\r
- for (String name : needsAddRole) {\r
- String team = "@" + name;\r
- String teamValues = allUsers.getProperty(team);\r
- teamValues += "," + role;\r
- allUsers.put(team, teamValues);\r
- }\r
-\r
- // remove role from team\r
- for (String name : needsRemoveRole) {\r
- String team = "@" + name;\r
- String[] values = allUsers.getProperty(team).split(",");\r
- StringBuilder sb = new StringBuilder();\r
- for (int i = 0; i < values.length; i++) {\r
- String value = values[i];\r
- if (!value.equalsIgnoreCase(role)) {\r
- sb.append(value);\r
- sb.append(',');\r
- }\r
- }\r
- sb.setLength(sb.length() - 1);\r
-\r
- // update properties\r
- allUsers.put(team, sb.toString());\r
- }\r
-\r
- // persist changes\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to set teamnames for role {0}!", role), t);\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Retrieve the team object for the specified team name.\r
- * \r
- * @param teamname\r
- * @return a team object or null\r
- * @since 0.8.0\r
- */\r
- @Override\r
- public TeamModel getTeamModel(String teamname) {\r
- read();\r
- TeamModel team = teams.get(teamname.toLowerCase());\r
- if (team != null) {\r
- // clone the model, otherwise all changes to this object are\r
- // live and unpersisted\r
- team = DeepCopier.copy(team);\r
- }\r
- return team;\r
- }\r
-\r
- /**\r
- * Updates/writes a complete team object.\r
- * \r
- * @param model\r
- * @return true if update is successful\r
- * @since 0.8.0\r
- */\r
- @Override\r
- public boolean updateTeamModel(TeamModel model) {\r
- return updateTeamModel(model.name, model);\r
- }\r
- \r
- /**\r
- * Updates/writes all specified team objects.\r
- * \r
- * @param models a list of team models\r
- * @return true if update is successful\r
- * @since 1.2.0\r
- */\r
- public boolean updateTeamModels(Collection<TeamModel> models) {\r
- try {\r
- Properties allUsers = read();\r
- for (TeamModel model : models) {\r
- updateTeamCache(allUsers, model.name, model);\r
- }\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to update {0} team models!", models.size()), t);\r
- }\r
- return false;\r
- }\r
-\r
- /**\r
- * Updates/writes and replaces a complete team object keyed by teamname.\r
- * This method allows for renaming a team.\r
- * \r
- * @param teamname\r
- * the old teamname\r
- * @param model\r
- * the team object to use for teamname\r
- * @return true if update is successful\r
- * @since 0.8.0\r
- */\r
- @Override\r
- public boolean updateTeamModel(String teamname, TeamModel model) {\r
- try {\r
- Properties allUsers = read();\r
- updateTeamCache(allUsers, teamname, model);\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to update team model {0}!", model.name), t);\r
- }\r
- return false;\r
- }\r
-\r
- private void updateTeamCache(Properties allUsers, String teamname, TeamModel model) {\r
- StringBuilder sb = new StringBuilder();\r
- List<String> roles;\r
- if (model.permissions == null) {\r
- // legacy, use repository list\r
- if (model.repositories != null) {\r
- roles = new ArrayList<String>(model.repositories);\r
- } else {\r
- roles = new ArrayList<String>();\r
- }\r
- } else {\r
- // discrete repository permissions\r
- roles = new ArrayList<String>();\r
- for (Map.Entry<String, AccessPermission> entry : model.permissions.entrySet()) {\r
- if (entry.getValue().exceeds(AccessPermission.NONE)) {\r
- // code:repository (e.g. RW+:~james/myrepo.git\r
- roles.add(entry.getValue().asRole(entry.getKey()));\r
- }\r
- }\r
- }\r
- \r
- // Permissions\r
- if (model.canAdmin) {\r
- roles.add(Constants.ADMIN_ROLE);\r
- }\r
- if (model.canFork) {\r
- roles.add(Constants.FORK_ROLE);\r
- }\r
- if (model.canCreate) {\r
- roles.add(Constants.CREATE_ROLE);\r
- }\r
-\r
- for (String role : roles) {\r
- sb.append(role);\r
- sb.append(',');\r
- }\r
- \r
- if (!ArrayUtils.isEmpty(model.users)) {\r
- for (String user : model.users) {\r
- sb.append('!');\r
- sb.append(user);\r
- sb.append(',');\r
- }\r
- }\r
- if (!ArrayUtils.isEmpty(model.mailingLists)) {\r
- for (String address : model.mailingLists) {\r
- sb.append('&');\r
- sb.append(address);\r
- sb.append(',');\r
- }\r
- }\r
- if (!ArrayUtils.isEmpty(model.preReceiveScripts)) {\r
- for (String script : model.preReceiveScripts) {\r
- sb.append('^');\r
- sb.append(script);\r
- sb.append(',');\r
- }\r
- }\r
- if (!ArrayUtils.isEmpty(model.postReceiveScripts)) {\r
- for (String script : model.postReceiveScripts) {\r
- sb.append('%');\r
- sb.append(script);\r
- sb.append(',');\r
- }\r
- }\r
- // trim trailing comma\r
- sb.setLength(sb.length() - 1);\r
- allUsers.remove("@" + teamname);\r
- allUsers.put("@" + model.name, sb.toString());\r
-\r
- // update team cache\r
- teams.remove(teamname.toLowerCase());\r
- teams.put(model.name.toLowerCase(), model);\r
- }\r
-\r
- /**\r
- * Deletes the team object from the user service.\r
- * \r
- * @param model\r
- * @return true if successful\r
- * @since 0.8.0\r
- */\r
- @Override\r
- public boolean deleteTeamModel(TeamModel model) {\r
- return deleteTeam(model.name);\r
- }\r
-\r
- /**\r
- * Delete the team object with the specified teamname\r
- * \r
- * @param teamname\r
- * @return true if successful\r
- * @since 0.8.0\r
- */\r
- @Override\r
- public boolean deleteTeam(String teamname) {\r
- Properties allUsers = read();\r
- teams.remove(teamname.toLowerCase());\r
- allUsers.remove("@" + teamname);\r
- try {\r
- write(allUsers);\r
- return true;\r
- } catch (Throwable t) {\r
- logger.error(MessageFormat.format("Failed to delete team {0}!", teamname), t);\r
- }\r
- return false;\r
- }\r
-}\r