James Moger
2012-07-11 a31cf95ac0787eb559cb78f48c52bc6b79e970d8
src/com/gitblit/ConfigUserService.java
@@ -20,6 +20,7 @@
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
@@ -34,6 +35,7 @@
import com.gitblit.models.TeamModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.ArrayUtils;
import com.gitblit.utils.DeepCopier;
import com.gitblit.utils.StringUtils;
@@ -58,10 +60,22 @@
   private static final String USER = "user";
   private static final String PASSWORD = "password";
   private static final String DISPLAYNAME = "displayName";
   private static final String EMAILADDRESS = "emailAddress";
   private static final String COOKIE = "cookie";
   private static final String REPOSITORY = "repository";
   private static final String ROLE = "role";
   private static final String MAILINGLIST = "mailingList";
   private static final String PRERECEIVE = "preReceiveScript";
   private static final String POSTRECEIVE = "postReceiveScript";
   private final File realmFile;
@@ -74,6 +88,8 @@
   private final Map<String, TeamModel> teams = new ConcurrentHashMap<String, TeamModel>();
   private volatile long lastModified;
   private volatile boolean forceReload;
   public ConfigUserService(File realmFile) {
      this.realmFile = realmFile;
@@ -89,6 +105,49 @@
   public void setup(IStoredSettings settings) {
   }
   /**
    * Does the user service support changes to credentials?
    *
    * @return true or false
    * @since 1.0.0
    */
   @Override
   public boolean supportsCredentialChanges() {
      return true;
   }
   /**
    * Does the user service support changes to user display name?
    *
    * @return true or false
    * @since 1.0.0
    */
   @Override
   public boolean supportsDisplayNameChanges() {
      return true;
   }
   /**
    * Does the user service support changes to user email address?
    *
    * @return true or false
    * @since 1.0.0
    */
   @Override
   public boolean supportsEmailAddressChanges() {
      return true;
   }
   /**
    * Does the user service support changes to team memberships?
    *
    * @return true or false
    * @since 1.0.0
    */
   public boolean supportsTeamMembershipChanges() {
      return true;
   }
   /**
    * Does the user service support cookie authentication?
    * 
@@ -106,11 +165,13 @@
    * @return cookie value
    */
   @Override
   public char[] getCookie(UserModel model) {
   public String getCookie(UserModel model) {
      if (!StringUtils.isEmpty(model.cookie)) {
         return model.cookie;
      }
      read();
      UserModel storedModel = users.get(model.username.toLowerCase());
      String cookie = StringUtils.getSHA1(model.username + storedModel.password);
      return cookie.toCharArray();
      return storedModel.cookie;
   }
   /**
@@ -168,6 +229,15 @@
      return returnedUser;
   }
   /**
    * Logout a user.
    *
    * @param user
    */
   @Override
   public void logout(UserModel user) {
   }
   /**
    * Retrieve the user object for the specified username.
    * 
@@ -301,9 +371,25 @@
   public List<String> getAllTeamNames() {
      read();
      List<String> list = new ArrayList<String>(teams.keySet());
      Collections.sort(list);
      return list;
   }
   /**
    * Returns the list of all teams available to the login service.
    *
    * @return list of all teams
    * @since 0.8.0
    */
   @Override
   public List<TeamModel> getAllTeams() {
      read();
      List<TeamModel> list = new ArrayList<TeamModel>(teams.values());
      list = DeepCopier.copy(list);
      Collections.sort(list);
      return list;
   }
   /**
    * Returns the list of all users who are allowed to bypass the access
    * restriction placed on the specified repository.
@@ -326,6 +412,7 @@
      } catch (Throwable t) {
         logger.error(MessageFormat.format("Failed to get teamnames for role {0}!", role), t);
      }
      Collections.sort(list);
      return list;
   }
@@ -466,8 +553,23 @@
   public List<String> getAllUsernames() {
      read();
      List<String> list = new ArrayList<String>(users.keySet());
      Collections.sort(list);
      return list;
   }
   /**
    * Returns the list of all users available to the login service.
    *
    * @return list of all usernames
    */
   @Override
   public List<UserModel> getAllUsers() {
      read();
      List<UserModel> list = new ArrayList<UserModel>(users.values());
      list = DeepCopier.copy(list);
      Collections.sort(list);
      return list;
   }
   /**
    * Returns the list of all users who are allowed to bypass the access
@@ -491,6 +593,7 @@
      } catch (Throwable t) {
         logger.error(MessageFormat.format("Failed to get usernames for role {0}!", role), t);
      }
      Collections.sort(list);
      return list;
   }
@@ -613,7 +716,18 @@
      // write users
      for (UserModel model : users.values()) {
         config.setString(USER, model.username, PASSWORD, model.password);
         if (!StringUtils.isEmpty(model.password)) {
            config.setString(USER, model.username, PASSWORD, model.password);
         }
         if (!StringUtils.isEmpty(model.cookie)) {
            config.setString(USER, model.username, COOKIE, model.cookie);
         }
         if (!StringUtils.isEmpty(model.displayName)) {
            config.setString(USER, model.username, DISPLAYNAME, model.displayName);
         }
         if (!StringUtils.isEmpty(model.emailAddress)) {
            config.setString(USER, model.username, EMAILADDRESS, model.emailAddress);
         }
         // user roles
         List<String> roles = new ArrayList<String>();
@@ -623,12 +737,18 @@
         if (model.excludeFromFederation) {
            roles.add(Constants.NOT_FEDERATED_ROLE);
         }
         if (roles.size() == 0) {
            // we do this to ensure that user record with no password
            // is written.  otherwise, StoredConfig optimizes that account
            // away. :(
            roles.add(Constants.NO_ROLE);
         }
         config.setStringList(USER, model.username, ROLE, roles);
         // repository memberships
         // null check on "final" repositories because JSON-sourced UserModel
         // can have a null repositories object
         if (model.repositories != null) {
         if (!ArrayUtils.isEmpty(model.repositories)) {
            config.setStringList(USER, model.username, REPOSITORY, new ArrayList<String>(
                  model.repositories));
         }
@@ -638,19 +758,41 @@
      for (TeamModel model : teams.values()) {
         // null check on "final" repositories because JSON-sourced TeamModel
         // can have a null repositories object
         if (model.repositories != null) {
         if (!ArrayUtils.isEmpty(model.repositories)) {
            config.setStringList(TEAM, model.name, REPOSITORY, new ArrayList<String>(
                  model.repositories));
         }
         // null check on "final" users because JSON-sourced TeamModel
         // can have a null users object
         if (model.users != null) {
         if (!ArrayUtils.isEmpty(model.users)) {
            config.setStringList(TEAM, model.name, USER, new ArrayList<String>(model.users));
         }
         // null check on "final" mailing lists because JSON-sourced
         // TeamModel can have a null users object
         if (!ArrayUtils.isEmpty(model.mailingLists)) {
            config.setStringList(TEAM, model.name, MAILINGLIST, new ArrayList<String>(
                  model.mailingLists));
         }
         // null check on "final" preReceiveScripts because JSON-sourced
         // TeamModel can have a null preReceiveScripts object
         if (!ArrayUtils.isEmpty(model.preReceiveScripts)) {
            config.setStringList(TEAM, model.name, PRERECEIVE, model.preReceiveScripts);
         }
         // null check on "final" postReceiveScripts because JSON-sourced
         // TeamModel can have a null postReceiveScripts object
         if (!ArrayUtils.isEmpty(model.postReceiveScripts)) {
            config.setStringList(TEAM, model.name, POSTRECEIVE, model.postReceiveScripts);
         }
      }
      config.save();
      // manually set the forceReload flag because not all JVMs support real
      // millisecond resolution of lastModified. (issue-55)
      forceReload = true;
      // If the write is successful, delete the current file and rename
      // the temporary copy to the original filename.
@@ -675,7 +817,8 @@
    * Reads the realm file and rebuilds the in-memory lookup tables.
    */
   protected synchronized void read() {
      if (realmFile.exists() && (realmFile.lastModified() > lastModified)) {
      if (realmFile.exists() && (forceReload || (realmFile.lastModified() != lastModified))) {
         forceReload = false;
         lastModified = realmFile.lastModified();
         users.clear();
         cookies.clear();
@@ -686,8 +829,14 @@
            config.load();
            Set<String> usernames = config.getSubsections(USER);
            for (String username : usernames) {
               UserModel user = new UserModel(username);
               user.password = config.getString(USER, username, PASSWORD);
               UserModel user = new UserModel(username.toLowerCase());
               user.password = config.getString(USER, username, PASSWORD);
               user.displayName = config.getString(USER, username, DISPLAYNAME);
               user.emailAddress = config.getString(USER, username, EMAILADDRESS);
               user.cookie = config.getString(USER, username, COOKIE);
               if (StringUtils.isEmpty(user.cookie) && !StringUtils.isEmpty(user.password)) {
                  user.cookie = StringUtils.getSHA1(user.username + user.password);
               }
               // user roles
               Set<String> roles = new HashSet<String>(Arrays.asList(config.getStringList(
@@ -703,8 +852,10 @@
               }
               // update cache
               users.put(username, user);
               cookies.put(StringUtils.getSHA1(username + user.password), user);
               users.put(user.username, user);
               if (!StringUtils.isEmpty(user.cookie)) {
                  cookies.put(user.cookie, user);
               }
            }
            // load the teams
@@ -714,6 +865,12 @@
               team.addRepositories(Arrays.asList(config.getStringList(TEAM, teamname,
                     REPOSITORY)));
               team.addUsers(Arrays.asList(config.getStringList(TEAM, teamname, USER)));
               team.addMailingLists(Arrays.asList(config.getStringList(TEAM, teamname,
                     MAILINGLIST)));
               team.preReceiveScripts.addAll(Arrays.asList(config.getStringList(TEAM,
                     teamname, PRERECEIVE)));
               team.postReceiveScripts.addAll(Arrays.asList(config.getStringList(TEAM,
                     teamname, POSTRECEIVE)));
               teams.put(team.name.toLowerCase(), team);