/** * Updates/writes and replaces a complete user object keyed by username. This method allows for * renaming a user. * * @param username the old username * @param model the user object to use for username * @return true if update is successful */ @Override public boolean updateUserModel(String username, UserModel model) { try { Properties allUsers = read(); UserModel oldUser = getUserModel(username); ArrayList<String> roles = new ArrayList<String>(model.repositories); // Permissions if (model.canAdmin) { roles.add(Constants.ADMIN_ROLE); } if (model.excludeFromFederation) { roles.add(Constants.NOT_FEDERATED_ROLE); } StringBuilder sb = new StringBuilder(); sb.append(model.password); sb.append(','); for (String role : roles) { sb.append(role); sb.append(','); } // trim trailing comma sb.setLength(sb.length() - 1); allUsers.remove(username.toLowerCase()); allUsers.put(model.username.toLowerCase(), sb.toString()); // null check on "final" teams because JSON-sourced UserModel // can have a null teams object if (model.teams != null) { // update team cache for (TeamModel team : model.teams) { TeamModel t = getTeamModel(team.name); if (t == null) { // new team t = team; } t.removeUser(username); t.addUser(model.username); updateTeamCache(allUsers, t.name, t); } // check for implicit team removal if (oldUser != null) { for (TeamModel team : oldUser.teams) { if (!model.isTeamMember(team.name)) { team.removeUser(username); updateTeamCache(allUsers, team.name, team); } } } } write(allUsers); return true; } catch (Throwable t) { logger.error(MessageFormat.format("Failed to update user model {0}!", model.username), t); } return false; }
/** * Retrieve the user object for the specified username. * * @param username * @return a user object or null */ @Override public UserModel getUserModel(String username) { Properties allUsers = read(); String userInfo = allUsers.getProperty(username.toLowerCase()); if (userInfo == null) { return null; } UserModel model = new UserModel(username.toLowerCase()); String[] userValues = userInfo.split(","); model.password = userValues[0]; for (int i = 1; i < userValues.length; i++) { String role = userValues[i]; switch (role.charAt(0)) { case '#': // Permissions if (role.equalsIgnoreCase(Constants.ADMIN_ROLE)) { model.canAdmin = true; } else if (role.equalsIgnoreCase(Constants.NOT_FEDERATED_ROLE)) { model.excludeFromFederation = true; } break; default: model.addRepository(role); } } // set the teams for the user for (TeamModel team : teams.values()) { if (team.hasUser(username)) { model.teams.add(DeepCopier.copy(team)); } } return model; }
/** Reads the properties file and rebuilds the in-memory cookie lookup table. */ @Override protected synchronized Properties read() { long lastRead = lastModified(); Properties allUsers = super.read(); if (lastRead != lastModified()) { // reload hash cache cookies.clear(); teams.clear(); for (String username : allUsers.stringPropertyNames()) { String value = allUsers.getProperty(username); String[] roles = value.split(","); if (username.charAt(0) == '@') { // team definition TeamModel team = new TeamModel(username.substring(1)); List<String> repositories = new ArrayList<String>(); List<String> users = new ArrayList<String>(); List<String> mailingLists = new ArrayList<String>(); List<String> preReceive = new ArrayList<String>(); List<String> postReceive = new ArrayList<String>(); for (String role : roles) { if (role.charAt(0) == '!') { users.add(role.substring(1)); } else if (role.charAt(0) == '&') { mailingLists.add(role.substring(1)); } else if (role.charAt(0) == '^') { preReceive.add(role.substring(1)); } else if (role.charAt(0) == '%') { postReceive.add(role.substring(1)); } else { repositories.add(role); } } team.addRepositories(repositories); team.addUsers(users); team.addMailingLists(mailingLists); teams.put(team.name.toLowerCase(), team); } else { // user definition String password = roles[0]; cookies.put( StringUtils.getSHA1(username.toLowerCase() + password), username.toLowerCase()); } } } return allUsers; }
/** * Delete the user object with the specified username * * @param username * @return true if successful */ @Override public boolean deleteUser(String username) { try { // Read realm file Properties allUsers = read(); UserModel user = getUserModel(username); allUsers.remove(username); for (TeamModel team : user.teams) { TeamModel t = getTeamModel(team.name); if (t == null) { // new team t = team; } t.removeUser(username); updateTeamCache(allUsers, t.name, t); } write(allUsers); return true; } catch (Throwable t) { logger.error(MessageFormat.format("Failed to delete user {0}!", username), t); } return false; }
protected void setupPage(final TeamModel teamModel) { if (isCreate) { super.setupPage(getString("gb.newTeam"), ""); } else { super.setupPage(getString("gb.edit"), teamModel.name); } CompoundPropertyModel<TeamModel> model = new CompoundPropertyModel<TeamModel>(teamModel); List<String> repos = getAccessRestrictedRepositoryList(true, null); List<String> teamUsers = new ArrayList<String>(teamModel.users); List<String> preReceiveScripts = new ArrayList<String>(); List<String> postReceiveScripts = new ArrayList<String>(); final String oldName = teamModel.name; final List<RegistrantAccessPermission> permissions = teamModel.getRepositoryPermissions(); // users palette final Palette<UserChoice> users = new Palette<UserChoice>( "users", new ListModel<UserChoice>(getTeamUsers(teamUsers)), new CollectionModel<UserChoice>( sortByDisplayName(getTeamUsers(app().users().getAllUsernames()))), new ChoiceRenderer<UserChoice>(null, "userId"), 10, false); // pre-receive palette if (teamModel.preReceiveScripts != null) { preReceiveScripts.addAll(teamModel.preReceiveScripts); } final Palette<String> preReceivePalette = new Palette<String>( "preReceiveScripts", new ListModel<String>(preReceiveScripts), new CollectionModel<String>(app().repositories().getPreReceiveScriptsUnused(null)), new StringChoiceRenderer(), 12, true); // post-receive palette if (teamModel.postReceiveScripts != null) { postReceiveScripts.addAll(teamModel.postReceiveScripts); } final Palette<String> postReceivePalette = new Palette<String>( "postReceiveScripts", new ListModel<String>(postReceiveScripts), new CollectionModel<String>(app().repositories().getPostReceiveScriptsUnused(null)), new StringChoiceRenderer(), 12, true); Form<TeamModel> form = new Form<TeamModel>("editForm", model) { private static final long serialVersionUID = 1L; /* * (non-Javadoc) * * @see org.apache.wicket.markup.html.form.Form#onSubmit() */ @Override protected void onSubmit() { String teamname = teamModel.name; if (StringUtils.isEmpty(teamname)) { error(getString("gb.pleaseSetTeamName")); return; } if (isCreate) { TeamModel model = app().users().getTeamModel(teamname); if (model != null) { error(MessageFormat.format(getString("gb.teamNameUnavailable"), teamname)); return; } } // update team permissions for (RegistrantAccessPermission repositoryPermission : permissions) { teamModel.setRepositoryPermission( repositoryPermission.registrant, repositoryPermission.permission); } Iterator<UserChoice> selectedUsers = users.getSelectedChoices(); List<String> members = new ArrayList<String>(); while (selectedUsers.hasNext()) { members.add(selectedUsers.next().getUserId().toLowerCase()); } teamModel.users.clear(); teamModel.users.addAll(members); // set mailing lists String ml = mailingLists.getObject(); if (!StringUtils.isEmpty(ml)) { Set<String> list = new HashSet<String>(); for (String address : ml.split("(,|\\s)")) { if (StringUtils.isEmpty(address)) { continue; } list.add(address.toLowerCase()); } teamModel.mailingLists.clear(); teamModel.mailingLists.addAll(list); } // pre-receive scripts List<String> preReceiveScripts = new ArrayList<String>(); Iterator<String> pres = preReceivePalette.getSelectedChoices(); while (pres.hasNext()) { preReceiveScripts.add(pres.next()); } teamModel.preReceiveScripts.clear(); teamModel.preReceiveScripts.addAll(preReceiveScripts); // post-receive scripts List<String> postReceiveScripts = new ArrayList<String>(); Iterator<String> post = postReceivePalette.getSelectedChoices(); while (post.hasNext()) { postReceiveScripts.add(post.next()); } teamModel.postReceiveScripts.clear(); teamModel.postReceiveScripts.addAll(postReceiveScripts); try { if (isCreate) { app().gitblit().addTeam(teamModel); } else { app().gitblit().reviseTeam(oldName, teamModel); } } catch (GitBlitException e) { error(e.getMessage()); return; } setRedirect(false); if (isCreate) { // create another team info(MessageFormat.format(getString("gb.teamCreated"), teamModel.name)); } // back to users page setResponsePage(UsersPage.class); } }; // do not let the browser pre-populate these fields form.add(new SimpleAttributeModifier("autocomplete", "off")); // not all user services support manipulating team memberships boolean editMemberships = app().authentication().supportsTeamMembershipChanges(teamModel); // field names reflective match TeamModel fields form.add(new TextField<String>("name")); form.add(new CheckBox("canAdmin")); form.add( new CheckBox("canFork") .setEnabled(app().settings().getBoolean(Keys.web.allowForking, true))); form.add(new CheckBox("canCreate")); form.add(users.setEnabled(editMemberships)); mailingLists = new Model<String>( teamModel.mailingLists == null ? "" : StringUtils.flattenStrings(teamModel.mailingLists, " ")); form.add(new TextField<String>("mailingLists", mailingLists)); form.add( new RegistrantPermissionsPanel( "repositories", RegistrantType.REPOSITORY, repos, permissions, getAccessPermissions())); form.add(preReceivePalette); form.add( new BulletListPanel( "inheritedPreReceive", "inherited", app().repositories().getPreReceiveScriptsInherited(null))); form.add(postReceivePalette); form.add( new BulletListPanel( "inheritedPostReceive", "inherited", app().repositories().getPostReceiveScriptsInherited(null))); form.add(new Button("save")); Button cancel = new Button("cancel") { private static final long serialVersionUID = 1L; @Override public void onSubmit() { setResponsePage(UsersPage.class); } }; cancel.setDefaultFormProcessing(false); form.add(cancel); add(form); }
protected List<ProjectModel> getProjects(PageParameters params) { if (params == null) { return getProjectModels(); } boolean hasParameter = false; String regex = WicketUtils.getRegEx(params); String team = WicketUtils.getTeam(params); int daysBack = params.getInt("db", 0); int maxDaysBack = app().settings().getInteger(Keys.web.activityDurationMaximum, 30); List<ProjectModel> availableModels = getProjectModels(); Set<ProjectModel> models = new HashSet<ProjectModel>(); if (!StringUtils.isEmpty(regex)) { // filter the projects by the regex hasParameter = true; Pattern pattern = Pattern.compile(regex); for (ProjectModel model : availableModels) { if (pattern.matcher(model.name).find()) { models.add(model); } } } if (!StringUtils.isEmpty(team)) { // filter the projects by the specified teams hasParameter = true; List<String> teams = StringUtils.getStringsFromValue(team, ","); // need TeamModels first List<TeamModel> teamModels = new ArrayList<TeamModel>(); for (String name : teams) { TeamModel teamModel = app().users().getTeamModel(name); if (teamModel != null) { teamModels.add(teamModel); } } // brute-force our way through finding the matching models for (ProjectModel projectModel : availableModels) { for (String repositoryName : projectModel.repositories) { for (TeamModel teamModel : teamModels) { if (teamModel.hasRepositoryPermission(repositoryName)) { models.add(projectModel); } } } } } if (!hasParameter) { models.addAll(availableModels); } // time-filter the list if (daysBack > 0) { if (maxDaysBack > 0 && daysBack > maxDaysBack) { daysBack = maxDaysBack; } Calendar cal = Calendar.getInstance(); cal.set(Calendar.HOUR_OF_DAY, 0); cal.set(Calendar.MINUTE, 0); cal.set(Calendar.SECOND, 0); cal.set(Calendar.MILLISECOND, 0); cal.add(Calendar.DATE, -1 * daysBack); Date threshold = cal.getTime(); Set<ProjectModel> timeFiltered = new HashSet<ProjectModel>(); for (ProjectModel model : models) { if (model.lastChange.after(threshold)) { timeFiltered.add(model); } } models = timeFiltered; } List<ProjectModel> list = new ArrayList<ProjectModel>(models); Collections.sort(list); return list; }
/** * Mirrors a repository and, optionally, the server's users, and/or configuration settings from a * origin Gitblit instance. * * @param registration * @throws Exception */ private void pull(FederationModel registration) throws Exception { Map<String, RepositoryModel> repositories = FederationUtils.getRepositories(registration, true); String registrationFolder = registration.folder.toLowerCase().trim(); // confirm valid characters in server alias Character c = StringUtils.findInvalidCharacter(registrationFolder); if (c != null) { logger.error( MessageFormat.format( "Illegal character ''{0}'' in folder name ''{1}'' of federation registration {2}!", c, registrationFolder, registration.name)); return; } File repositoriesFolder = new File(GitBlit.getString(Keys.git.repositoriesFolder, "git")); File registrationFolderFile = new File(repositoriesFolder, registrationFolder); registrationFolderFile.mkdirs(); // Clone/Pull the repository for (Map.Entry<String, RepositoryModel> entry : repositories.entrySet()) { String cloneUrl = entry.getKey(); RepositoryModel repository = entry.getValue(); if (!repository.hasCommits) { logger.warn( MessageFormat.format( "Skipping federated repository {0} from {1} @ {2}. Repository is EMPTY.", repository.name, registration.name, registration.url)); registration.updateStatus(repository, FederationPullStatus.SKIPPED); continue; } // Determine local repository name String repositoryName; if (StringUtils.isEmpty(registrationFolder)) { repositoryName = repository.name; } else { repositoryName = registrationFolder + "/" + repository.name; } if (registration.bare) { // bare repository, ensure .git suffix if (!repositoryName.toLowerCase().endsWith(DOT_GIT_EXT)) { repositoryName += DOT_GIT_EXT; } } else { // normal repository, strip .git suffix if (repositoryName.toLowerCase().endsWith(DOT_GIT_EXT)) { repositoryName = repositoryName.substring(0, repositoryName.indexOf(DOT_GIT_EXT)); } } // confirm that the origin of any pre-existing repository matches // the clone url String fetchHead = null; Repository existingRepository = GitBlit.self().getRepository(repositoryName); if (existingRepository == null && GitBlit.self().isCollectingGarbage(repositoryName)) { logger.warn( MessageFormat.format( "Skipping local repository {0}, busy collecting garbage", repositoryName)); continue; } if (existingRepository != null) { StoredConfig config = existingRepository.getConfig(); config.load(); String origin = config.getString("remote", "origin", "url"); RevCommit commit = JGitUtils.getCommit(existingRepository, org.eclipse.jgit.lib.Constants.FETCH_HEAD); if (commit != null) { fetchHead = commit.getName(); } existingRepository.close(); if (!origin.startsWith(registration.url)) { logger.warn( MessageFormat.format( "Skipping federated repository {0} from {1} @ {2}. Origin does not match, consider EXCLUDING.", repository.name, registration.name, registration.url)); registration.updateStatus(repository, FederationPullStatus.SKIPPED); continue; } } // clone/pull this repository CredentialsProvider credentials = new UsernamePasswordCredentialsProvider(Constants.FEDERATION_USER, registration.token); logger.info( MessageFormat.format( "Pulling federated repository {0} from {1} @ {2}", repository.name, registration.name, registration.url)); CloneResult result = JGitUtils.cloneRepository( registrationFolderFile, repository.name, cloneUrl, registration.bare, credentials); Repository r = GitBlit.self().getRepository(repositoryName); RepositoryModel rm = GitBlit.self().getRepositoryModel(repositoryName); repository.isFrozen = registration.mirror; if (result.createdRepository) { // default local settings repository.federationStrategy = FederationStrategy.EXCLUDE; repository.isFrozen = registration.mirror; repository.showRemoteBranches = !registration.mirror; logger.info(MessageFormat.format(" cloning {0}", repository.name)); registration.updateStatus(repository, FederationPullStatus.MIRRORED); } else { // fetch and update boolean fetched = false; RevCommit commit = JGitUtils.getCommit(r, org.eclipse.jgit.lib.Constants.FETCH_HEAD); String newFetchHead = commit.getName(); fetched = fetchHead == null || !fetchHead.equals(newFetchHead); if (registration.mirror) { // mirror if (fetched) { // update local branches to match the remote tracking branches for (RefModel ref : JGitUtils.getRemoteBranches(r, false, -1)) { if (ref.displayName.startsWith("origin/")) { String branch = org.eclipse.jgit.lib.Constants.R_HEADS + ref.displayName.substring(ref.displayName.indexOf('/') + 1); String hash = ref.getReferencedObjectId().getName(); JGitUtils.setBranchRef(r, branch, hash); logger.info( MessageFormat.format( " resetting {0} of {1} to {2}", branch, repository.name, hash)); } } String newHead; if (StringUtils.isEmpty(repository.HEAD)) { newHead = newFetchHead; } else { newHead = repository.HEAD; } JGitUtils.setHEADtoRef(r, newHead); logger.info( MessageFormat.format( " resetting HEAD of {0} to {1}", repository.name, newHead)); registration.updateStatus(repository, FederationPullStatus.MIRRORED); } else { // indicate no commits pulled registration.updateStatus(repository, FederationPullStatus.NOCHANGE); } } else { // non-mirror if (fetched) { // indicate commits pulled to origin/master registration.updateStatus(repository, FederationPullStatus.PULLED); } else { // indicate no commits pulled registration.updateStatus(repository, FederationPullStatus.NOCHANGE); } } // preserve local settings repository.isFrozen = rm.isFrozen; repository.federationStrategy = rm.federationStrategy; // merge federation sets Set<String> federationSets = new HashSet<String>(); if (rm.federationSets != null) { federationSets.addAll(rm.federationSets); } if (repository.federationSets != null) { federationSets.addAll(repository.federationSets); } repository.federationSets = new ArrayList<String>(federationSets); // merge indexed branches Set<String> indexedBranches = new HashSet<String>(); if (rm.indexedBranches != null) { indexedBranches.addAll(rm.indexedBranches); } if (repository.indexedBranches != null) { indexedBranches.addAll(repository.indexedBranches); } repository.indexedBranches = new ArrayList<String>(indexedBranches); } // only repositories that are actually _cloned_ from the origin // Gitblit repository are marked as federated. If the origin // is from somewhere else, these repositories are not considered // "federated" repositories. repository.isFederated = cloneUrl.startsWith(registration.url); GitBlit.self().updateConfiguration(r, repository); r.close(); } IUserService userService = null; try { // Pull USERS // TeamModels are automatically pulled because they are contained // within the UserModel. The UserService creates unknown teams // and updates existing teams. Collection<UserModel> users = FederationUtils.getUsers(registration); if (users != null && users.size() > 0) { File realmFile = new File(registrationFolderFile, registration.name + "_users.conf"); realmFile.delete(); userService = new ConfigUserService(realmFile); for (UserModel user : users) { userService.updateUserModel(user.username, user); // merge the origin permissions and origin accounts into // the user accounts of this Gitblit instance if (registration.mergeAccounts) { // reparent all repository permissions if the local // repositories are stored within subfolders if (!StringUtils.isEmpty(registrationFolder)) { if (user.permissions != null) { // pulling from >= 1.2 version Map<String, AccessPermission> copy = new HashMap<String, AccessPermission>(user.permissions); user.permissions.clear(); for (Map.Entry<String, AccessPermission> entry : copy.entrySet()) { user.setRepositoryPermission( registrationFolder + "/" + entry.getKey(), entry.getValue()); } } else { // pulling from <= 1.1 version List<String> permissions = new ArrayList<String>(user.repositories); user.repositories.clear(); for (String permission : permissions) { user.addRepositoryPermission(registrationFolder + "/" + permission); } } } // insert new user or update local user UserModel localUser = GitBlit.self().getUserModel(user.username); if (localUser == null) { // create new local user GitBlit.self().updateUserModel(user.username, user, true); } else { // update repository permissions of local user if (user.permissions != null) { // pulling from >= 1.2 version Map<String, AccessPermission> copy = new HashMap<String, AccessPermission>(user.permissions); for (Map.Entry<String, AccessPermission> entry : copy.entrySet()) { localUser.setRepositoryPermission(entry.getKey(), entry.getValue()); } } else { // pulling from <= 1.1 version for (String repository : user.repositories) { localUser.addRepositoryPermission(repository); } } localUser.password = user.password; localUser.canAdmin = user.canAdmin; GitBlit.self().updateUserModel(localUser.username, localUser, false); } for (String teamname : GitBlit.self().getAllTeamnames()) { TeamModel team = GitBlit.self().getTeamModel(teamname); if (user.isTeamMember(teamname) && !team.hasUser(user.username)) { // new team member team.addUser(user.username); GitBlit.self().updateTeamModel(teamname, team, false); } else if (!user.isTeamMember(teamname) && team.hasUser(user.username)) { // remove team member team.removeUser(user.username); GitBlit.self().updateTeamModel(teamname, team, false); } // update team repositories TeamModel remoteTeam = user.getTeam(teamname); if (remoteTeam != null) { if (remoteTeam.permissions != null) { // pulling from >= 1.2 for (Map.Entry<String, AccessPermission> entry : remoteTeam.permissions.entrySet()) { team.setRepositoryPermission(entry.getKey(), entry.getValue()); } GitBlit.self().updateTeamModel(teamname, team, false); } else if (!ArrayUtils.isEmpty(remoteTeam.repositories)) { // pulling from <= 1.1 team.addRepositoryPermissions(remoteTeam.repositories); GitBlit.self().updateTeamModel(teamname, team, false); } } } } } } } catch (ForbiddenException e) { // ignore forbidden exceptions } catch (IOException e) { logger.warn( MessageFormat.format( "Failed to retrieve USERS from federated gitblit ({0} @ {1})", registration.name, registration.url), e); } try { // Pull TEAMS // We explicitly pull these even though they are embedded in // UserModels because it is possible to use teams to specify // mailing lists or push scripts without specifying users. if (userService != null) { Collection<TeamModel> teams = FederationUtils.getTeams(registration); if (teams != null && teams.size() > 0) { for (TeamModel team : teams) { userService.updateTeamModel(team); } } } } catch (ForbiddenException e) { // ignore forbidden exceptions } catch (IOException e) { logger.warn( MessageFormat.format( "Failed to retrieve TEAMS from federated gitblit ({0} @ {1})", registration.name, registration.url), e); } try { // Pull SETTINGS Map<String, String> settings = FederationUtils.getSettings(registration); if (settings != null && settings.size() > 0) { Properties properties = new Properties(); properties.putAll(settings); FileOutputStream os = new FileOutputStream( new File( registrationFolderFile, registration.name + "_" + Constants.PROPERTIES_FILE)); properties.store(os, null); os.close(); } } catch (ForbiddenException e) { // ignore forbidden exceptions } catch (IOException e) { logger.warn( MessageFormat.format( "Failed to retrieve SETTINGS from federated gitblit ({0} @ {1})", registration.name, registration.url), e); } try { // Pull SCRIPTS Map<String, String> scripts = FederationUtils.getScripts(registration); if (scripts != null && scripts.size() > 0) { for (Map.Entry<String, String> script : scripts.entrySet()) { String scriptName = script.getKey(); if (scriptName.endsWith(".groovy")) { scriptName = scriptName.substring(0, scriptName.indexOf(".groovy")); } File file = new File(registrationFolderFile, registration.name + "_" + scriptName + ".groovy"); FileUtils.writeContent(file, script.getValue()); } } } catch (ForbiddenException e) { // ignore forbidden exceptions } catch (IOException e) { logger.warn( MessageFormat.format( "Failed to retrieve SCRIPTS from federated gitblit ({0} @ {1})", registration.name, registration.url), e); } }