James Moger
2011-11-01 c25a1d65ed2c94b65741d81862a7612ae12bdf76
commit | author | age
831469 1 /*
JM 2  * Copyright 2011 gitblit.com.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.gitblit;
17
18 import java.text.MessageFormat;
19 import java.util.ArrayList;
20 import java.util.Date;
21 import java.util.HashMap;
22 import java.util.List;
23 import java.util.Map;
24
25 import javax.servlet.http.HttpServletResponse;
26
27 import com.gitblit.Constants.FederationRequest;
28 import com.gitblit.models.FederationModel;
29 import com.gitblit.models.FederationProposal;
30 import com.gitblit.models.UserModel;
4aafd4 31 import com.gitblit.utils.FederationUtils;
831469 32 import com.gitblit.utils.HttpUtils;
JM 33 import com.gitblit.utils.StringUtils;
34 import com.gitblit.utils.TimeUtils;
35
36 /**
37  * Handles federation requests.
38  * 
39  * @author James Moger
40  * 
41  */
93f0b1 42 public class FederationServlet extends JsonServlet {
831469 43
JM 44     private static final long serialVersionUID = 1L;
45
46     public FederationServlet() {
47         super();
48     }
49
50     /**
93f0b1 51      * Processes a federation request.
831469 52      * 
JM 53      * @param request
54      * @param response
55      * @throws javax.servlet.ServletException
56      * @throws java.io.IOException
57      */
93f0b1 58
JM 59     @Override
60     protected void processRequest(javax.servlet.http.HttpServletRequest request,
831469 61             javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
JM 62             java.io.IOException {
4aafd4 63         FederationRequest reqType = FederationRequest.fromName(request.getParameter("req"));
JM 64         logger.info(MessageFormat.format("Federation {0} request from {1}", reqType,
65                 request.getRemoteAddr()));
66
67         if (FederationRequest.POKE.equals(reqType)) {
68             // Gitblit always responds to POKE requests to verify a connection
69             logger.info("Received federation POKE from " + request.getRemoteAddr());
70             return;
71         }
72
831469 73         if (!GitBlit.getBoolean(Keys.git.enableGitServlet, true)) {
JM 74             logger.warn(Keys.git.enableGitServlet + " must be set TRUE for federation requests.");
75             response.sendError(HttpServletResponse.SC_FORBIDDEN);
76             return;
77         }
78
2c32fd 79         String uuid = GitBlit.getString(Keys.federation.passphrase, "");
831469 80         if (StringUtils.isEmpty(uuid)) {
2c32fd 81             logger.warn(Keys.federation.passphrase
JM 82                     + " is not properly set!  Federation request denied.");
831469 83             response.sendError(HttpServletResponse.SC_FORBIDDEN);
JM 84             return;
85         }
86
87         if (FederationRequest.PROPOSAL.equals(reqType)) {
88             // Receive a gitblit federation proposal
93f0b1 89             FederationProposal proposal = deserialize(request, response, FederationProposal.class);
JM 90             if (proposal == null) {
831469 91                 return;
JM 92             }
93f0b1 93             
dd9ae7 94             // reject proposal, if not receipt prohibited
JM 95             if (!GitBlit.getBoolean(Keys.federation.allowProposals, false)) {
96                 logger.error(MessageFormat.format("Rejected {0} federation proposal from {1}",
97                         proposal.tokenType.name(), proposal.url));
98                 response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);
4aafd4 99                 return;
JM 100             }
101
102             // poke the origin Gitblit instance that is proposing federation
103             boolean poked = false;
104             try {
105                 poked = FederationUtils.poke(proposal.url);
106             } catch (Exception e) {
107                 logger.error("Failed to poke origin", e);
108             }
109             if (!poked) {
110                 logger.error(MessageFormat.format("Failed to send federation poke to {0}",
111                         proposal.url));
112                 response.setStatus(HttpServletResponse.SC_NOT_ACCEPTABLE);
dd9ae7 113                 return;
JM 114             }
115
2179fb 116             String url = HttpUtils.getGitblitURL(request);
JM 117             GitBlit.self().submitFederationProposal(proposal, url);
831469 118             logger.info(MessageFormat.format(
JM 119                     "Submitted {0} federation proposal to pull {1} repositories from {2}",
dd9ae7 120                     proposal.tokenType.name(), proposal.repositories.size(), proposal.url));
831469 121             response.setStatus(HttpServletResponse.SC_OK);
JM 122             return;
123         }
124
125         if (FederationRequest.STATUS.equals(reqType)) {
126             // Receive a gitblit federation status acknowledgment
127             String remoteId = StringUtils.decodeFromHtml(request.getParameter("url"));
128             String identification = MessageFormat.format("{0} ({1})", remoteId,
129                     request.getRemoteAddr());
130
93f0b1 131             // deserialize the status data
JM 132             FederationModel results = deserialize(request, response, FederationModel.class);
133             if (results == null) {
831469 134                 return;
JM 135             }
136
137             // setup the last and netx pull dates
138             results.lastPull = new Date();
139             int mins = TimeUtils.convertFrequencyToMinutes(results.frequency);
140             results.nextPull = new Date(System.currentTimeMillis() + (mins * 60 * 1000L));
141
142             // acknowledge the receipt of status
143             GitBlit.self().acknowledgeFederationStatus(identification, results);
144             logger.info(MessageFormat.format(
145                     "Received status of {0} federated repositories from {1}", results
146                             .getStatusList().size(), identification));
147             response.setStatus(HttpServletResponse.SC_OK);
148             return;
149         }
150
151         // Determine the federation tokens for this gitblit instance
4aafd4 152         String token = request.getParameter("token");
831469 153         List<String> tokens = GitBlit.self().getFederationTokens();
JM 154         if (!tokens.contains(token)) {
155             logger.warn(MessageFormat.format(
156                     "Received Federation token ''{0}'' does not match the server tokens", token));
157             response.sendError(HttpServletResponse.SC_FORBIDDEN);
158             return;
159         }
160
161         Object result = null;
162         if (FederationRequest.PULL_REPOSITORIES.equals(reqType)) {
2179fb 163             String gitblitUrl = HttpUtils.getGitblitURL(request);
dd9ae7 164             result = GitBlit.self().getRepositories(gitblitUrl, token);
831469 165         } else {
JM 166             if (FederationRequest.PULL_SETTINGS.equals(reqType)) {
167                 // pull settings
168                 if (!GitBlit.self().validateFederationRequest(reqType, token)) {
169                     // invalid token to pull users or settings
170                     logger.warn(MessageFormat.format(
171                             "Federation token from {0} not authorized to pull SETTINGS",
172                             request.getRemoteAddr()));
173                     response.sendError(HttpServletResponse.SC_FORBIDDEN);
174                     return;
175                 }
176                 Map<String, String> settings = new HashMap<String, String>();
177                 List<String> keys = GitBlit.getAllKeys(null);
178                 for (String key : keys) {
179                     settings.put(key, GitBlit.getString(key, ""));
180                 }
181                 result = settings;
182             } else if (FederationRequest.PULL_USERS.equals(reqType)) {
183                 // pull users
184                 if (!GitBlit.self().validateFederationRequest(reqType, token)) {
185                     // invalid token to pull users or settings
186                     logger.warn(MessageFormat.format(
187                             "Federation token from {0} not authorized to pull USERS",
188                             request.getRemoteAddr()));
189                     response.sendError(HttpServletResponse.SC_FORBIDDEN);
190                     return;
191                 }
192                 List<String> usernames = GitBlit.self().getAllUsernames();
193                 List<UserModel> users = new ArrayList<UserModel>();
194                 for (String username : usernames) {
195                     UserModel user = GitBlit.self().getUserModel(username);
196                     if (!user.excludeFromFederation) {
197                         users.add(user);
198                     }
199                 }
200                 result = users;
201             }
202         }
203
93f0b1 204         // send the result of the request
JM 205         serialize(response, result);
831469 206     }
JM 207 }