diff options
Diffstat (limited to 'src/main/java/com/gitblit/FederationServlet.java')
-rw-r--r-- | src/main/java/com/gitblit/FederationServlet.java | 264 |
1 files changed, 264 insertions, 0 deletions
diff --git a/src/main/java/com/gitblit/FederationServlet.java b/src/main/java/com/gitblit/FederationServlet.java new file mode 100644 index 00000000..e7720508 --- /dev/null +++ b/src/main/java/com/gitblit/FederationServlet.java @@ -0,0 +1,264 @@ +/*
+ * Copyright 2011 gitblit.com.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.gitblit;
+
+import java.io.File;
+import java.text.MessageFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.servlet.http.HttpServletResponse;
+
+import com.gitblit.Constants.FederationRequest;
+import com.gitblit.models.FederationModel;
+import com.gitblit.models.FederationProposal;
+import com.gitblit.models.TeamModel;
+import com.gitblit.models.UserModel;
+import com.gitblit.utils.FederationUtils;
+import com.gitblit.utils.FileUtils;
+import com.gitblit.utils.HttpUtils;
+import com.gitblit.utils.StringUtils;
+import com.gitblit.utils.TimeUtils;
+
+/**
+ * Handles federation requests.
+ *
+ * @author James Moger
+ *
+ */
+public class FederationServlet extends JsonServlet {
+
+ private static final long serialVersionUID = 1L;
+
+ public FederationServlet() {
+ super();
+ }
+
+ /**
+ * Processes a federation request.
+ *
+ * @param request
+ * @param response
+ * @throws javax.servlet.ServletException
+ * @throws java.io.IOException
+ */
+
+ @Override
+ protected void processRequest(javax.servlet.http.HttpServletRequest request,
+ javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
+ java.io.IOException {
+ FederationRequest reqType = FederationRequest.fromName(request.getParameter("req"));
+ logger.info(MessageFormat.format("Federation {0} request from {1}", reqType,
+ request.getRemoteAddr()));
+
+ if (FederationRequest.POKE.equals(reqType)) {
+ // Gitblit always responds to POKE requests to verify a connection
+ logger.info("Received federation POKE from " + request.getRemoteAddr());
+ return;
+ }
+
+ if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
+ logger.warn(Keys.git.enableGitServlet + " must be set TRUE for federation requests.");
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ String uuid = GitBlit.getString(Keys.federation.passphrase, "");
+ if (StringUtils.isEmpty(uuid)) {
+ logger.warn(Keys.federation.passphrase
+ + " is not properly set! Federation request denied.");
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ if (FederationRequest.PROPOSAL.equals(reqType)) {
+ // Receive a gitblit federation proposal
+ FederationProposal proposal = deserialize(request, response, FederationProposal.class);
+ if (proposal == null) {
+ return;
+ }
+
+ // reject proposal, if not receipt prohibited
+ if (!GitBlit.getBoolean(Keys.federation.allowProposals, false)) {
+ logger.error(MessageFormat.format("Rejected {0} federation proposal from {1}",
+ proposal.tokenType.name(), proposal.url));
+ response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
+ return;
+ }
+
+ // poke the origin Gitblit instance that is proposing federation
+ boolean poked = false;
+ try {
+ poked = FederationUtils.poke(proposal.url);
+ } catch (Exception e) {
+ logger.error("Failed to poke origin", e);
+ }
+ if (!poked) {
+ logger.error(MessageFormat.format("Failed to send federation poke to {0}",
+ proposal.url));
+ response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
+ return;
+ }
+
+ String url = HttpUtils.getGitblitURL(request);
+ GitBlit.self().submitFederationProposal(proposal, url);
+ logger.info(MessageFormat.format(
+ "Submitted {0} federation proposal to pull {1} repositories from {2}",
+ proposal.tokenType.name(), proposal.repositories.size(), proposal.url));
+ response.setStatus(HttpServletResponse.SC_OK);
+ return;
+ }
+
+ if (FederationRequest.STATUS.equals(reqType)) {
+ // Receive a gitblit federation status acknowledgment
+ String remoteId = StringUtils.decodeFromHtml(request.getParameter("url"));
+ String identification = MessageFormat.format("{0} ({1})", remoteId,
+ request.getRemoteAddr());
+
+ // deserialize the status data
+ FederationModel results = deserialize(request, response, FederationModel.class);
+ if (results == null) {
+ return;
+ }
+
+ // setup the last and netx pull dates
+ results.lastPull = new Date();
+ int mins = TimeUtils.convertFrequencyToMinutes(results.frequency);
+ results.nextPull = new Date(System.currentTimeMillis() + (mins * 60 * 1000L));
+
+ // acknowledge the receipt of status
+ GitBlit.self().acknowledgeFederationStatus(identification, results);
+ logger.info(MessageFormat.format(
+ "Received status of {0} federated repositories from {1}", results
+ .getStatusList().size(), identification));
+ response.setStatus(HttpServletResponse.SC_OK);
+ return;
+ }
+
+ // Determine the federation tokens for this gitblit instance
+ String token = request.getParameter("token");
+ List<String> tokens = GitBlit.self().getFederationTokens();
+ if (!tokens.contains(token)) {
+ logger.warn(MessageFormat.format(
+ "Received Federation token ''{0}'' does not match the server tokens", token));
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+
+ Object result = null;
+ if (FederationRequest.PULL_REPOSITORIES.equals(reqType)) {
+ String gitblitUrl = HttpUtils.getGitblitURL(request);
+ result = GitBlit.self().getRepositories(gitblitUrl, token);
+ } else {
+ if (FederationRequest.PULL_SETTINGS.equals(reqType)) {
+ // pull settings
+ if (!GitBlit.self().validateFederationRequest(reqType, token)) {
+ // invalid token to pull users or settings
+ logger.warn(MessageFormat.format(
+ "Federation token from {0} not authorized to pull SETTINGS",
+ request.getRemoteAddr()));
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ Map<String, String> settings = new HashMap<String, String>();
+ List<String> keys = GitBlit.getAllKeys(null);
+ for (String key : keys) {
+ settings.put(key, GitBlit.getString(key, ""));
+ }
+ result = settings;
+ } else if (FederationRequest.PULL_USERS.equals(reqType)) {
+ // pull users
+ if (!GitBlit.self().validateFederationRequest(reqType, token)) {
+ // invalid token to pull users or settings
+ logger.warn(MessageFormat.format(
+ "Federation token from {0} not authorized to pull USERS",
+ request.getRemoteAddr()));
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ List<String> usernames = GitBlit.self().getAllUsernames();
+ List<UserModel> users = new ArrayList<UserModel>();
+ for (String username : usernames) {
+ UserModel user = GitBlit.self().getUserModel(username);
+ if (!user.excludeFromFederation) {
+ users.add(user);
+ }
+ }
+ result = users;
+ } else if (FederationRequest.PULL_TEAMS.equals(reqType)) {
+ // pull teams
+ if (!GitBlit.self().validateFederationRequest(reqType, token)) {
+ // invalid token to pull teams
+ logger.warn(MessageFormat.format(
+ "Federation token from {0} not authorized to pull TEAMS",
+ request.getRemoteAddr()));
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ List<String> teamnames = GitBlit.self().getAllTeamnames();
+ List<TeamModel> teams = new ArrayList<TeamModel>();
+ for (String teamname : teamnames) {
+ TeamModel user = GitBlit.self().getTeamModel(teamname);
+ teams.add(user);
+ }
+ result = teams;
+ } else if (FederationRequest.PULL_SCRIPTS.equals(reqType)) {
+ // pull scripts
+ if (!GitBlit.self().validateFederationRequest(reqType, token)) {
+ // invalid token to pull script
+ logger.warn(MessageFormat.format(
+ "Federation token from {0} not authorized to pull SCRIPTS",
+ request.getRemoteAddr()));
+ response.sendError(HttpServletResponse.SC_FORBIDDEN);
+ return;
+ }
+ Map<String, String> scripts = new HashMap<String, String>();
+
+ Set<String> names = new HashSet<String>();
+ names.addAll(GitBlit.getStrings(Keys.groovy.preReceiveScripts));
+ names.addAll(GitBlit.getStrings(Keys.groovy.postReceiveScripts));
+ for (TeamModel team : GitBlit.self().getAllTeams()) {
+ names.addAll(team.preReceiveScripts);
+ names.addAll(team.postReceiveScripts);
+ }
+ File scriptsFolder = GitBlit.getFileOrFolder(Keys.groovy.scriptsFolder, "groovy");
+ for (String name : names) {
+ File file = new File(scriptsFolder, name);
+ if (!file.exists() && !file.getName().endsWith(".groovy")) {
+ file = new File(scriptsFolder, name + ".groovy");
+ }
+ if (file.exists()) {
+ // read the script
+ String content = FileUtils.readContent(file, "\n");
+ scripts.put(name, content);
+ } else {
+ // missing script?!
+ logger.warn(MessageFormat.format("Failed to find push script \"{0}\"", name));
+ }
+ }
+ result = scripts;
+ }
+ }
+
+ // send the result of the request
+ serialize(response, result);
+ }
+}
|