James Moger
2015-11-22 ed552ba47c02779c270ffd62841d6d1048dade70
commit | author | age
93f0b1 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  */
7bf6e1 16 package com.gitblit.servlet;
93f0b1 17
ca9d0f 18 import java.io.IOException;
93f0b1 19 import java.text.MessageFormat;
JM 20 import java.util.ArrayList;
31abc2 21 import java.util.Collection;
93f0b1 22 import java.util.HashMap;
JM 23 import java.util.List;
24 import java.util.Map;
25
cdb2fe 26 import com.google.inject.Inject;
JM 27 import com.google.inject.Singleton;
ca9d0f 28 import javax.servlet.ServletException;
JM 29 import javax.servlet.http.HttpServletRequest;
93f0b1 30 import javax.servlet.http.HttpServletResponse;
JM 31
c75304 32 import org.eclipse.jgit.lib.Repository;
JM 33
7bf6e1 34 import com.gitblit.Constants;
c5069a 35 import com.gitblit.Constants.RpcRequest;
7bf6e1 36 import com.gitblit.GitBlitException;
JM 37 import com.gitblit.IStoredSettings;
38 import com.gitblit.Keys;
3a9e76 39 import com.gitblit.manager.IGitblit;
813a1f 40 import com.gitblit.models.RefModel;
JM 41 import com.gitblit.models.RegistrantAccessPermission;
42 import com.gitblit.models.RepositoryModel;
43 import com.gitblit.models.ServerSettings;
44 import com.gitblit.models.TeamModel;
45 import com.gitblit.models.UserModel;
a5ae3d 46 import com.gitblit.utils.DeepCopier;
93f0b1 47 import com.gitblit.utils.HttpUtils;
c75304 48 import com.gitblit.utils.JGitUtils;
31abc2 49 import com.gitblit.utils.RpcUtils;
a5ae3d 50 import com.gitblit.utils.StringUtils;
93f0b1 51
JM 52 /**
53  * Handles remote procedure calls.
699e71 54  *
93f0b1 55  * @author James Moger
JM 56  */
1b34b0 57 @Singleton
93f0b1 58 public class RpcServlet extends JsonServlet {
JM 59
311ae9 60     private static final long serialVersionUID = 1L;
f08aab 61
311ae9 62     public static final int PROTOCOL_VERSION = 8;
93f0b1 63
311ae9 64     private IStoredSettings settings;
cacf8b 65
311ae9 66     private IGitblit gitblit;
cacf8b 67
1b34b0 68     @Inject
JM 69     public RpcServlet(IStoredSettings settings, IGitblit gitblit) {
70         this.settings = settings;
71         this.gitblit = gitblit;
311ae9 72     }
93f0b1 73
311ae9 74     /**
JM 75      * Processes an rpc request.
76      *
77      * @param request
78      * @param response
79      * @throws javax.servlet.ServletException
80      * @throws java.io.IOException
81      */
82     @Override
83     protected void processRequest(HttpServletRequest request, HttpServletResponse response) throws ServletException,
84             IOException {
85         RpcRequest reqType = RpcRequest.fromName(request.getParameter("req"));
86         String objectName = request.getParameter("name");
87         logger.info(MessageFormat.format("Rpc {0} request from {1}", reqType, request.getRemoteAddr()));
db4f6b 88
311ae9 89         UserModel user = (UserModel) request.getUserPrincipal();
ec5a88 90
311ae9 91         boolean allowManagement = user != null && user.canAdmin()
JM 92                 && settings.getBoolean(Keys.web.enableRpcManagement, false);
ec5a88 93
311ae9 94         boolean allowAdmin = user != null && user.canAdmin()
JM 95                 && settings.getBoolean(Keys.web.enableRpcAdministration, false);
93f0b1 96
311ae9 97         Object result = null;
JM 98         if (RpcRequest.GET_PROTOCOL.equals(reqType)) {
99             // Return the protocol version
100             result = PROTOCOL_VERSION;
101         } else if (RpcRequest.LIST_REPOSITORIES.equals(reqType)) {
102             // Determine the Gitblit clone url
103             String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null);
104             if (StringUtils.isEmpty(gitblitUrl)) {
105                 gitblitUrl = HttpUtils.getGitblitURL(request);
106             }
107             StringBuilder sb = new StringBuilder();
108             sb.append(gitblitUrl);
109             sb.append(Constants.R_PATH);
110             sb.append("{0}");
111             String cloneUrl = sb.toString();
93f0b1 112
311ae9 113             // list repositories
JM 114             List<RepositoryModel> list = gitblit.getRepositoryModels(user);
115             Map<String, RepositoryModel> repositories = new HashMap<String, RepositoryModel>();
116             for (RepositoryModel model : list) {
117                 String url = MessageFormat.format(cloneUrl, model.name);
118                 repositories.put(url, model);
119             }
120             result = repositories;
121         } else if (RpcRequest.LIST_BRANCHES.equals(reqType)) {
122             // list all local branches in all repositories accessible to user
123             Map<String, List<String>> localBranches = new HashMap<String, List<String>>();
124             List<RepositoryModel> models = gitblit.getRepositoryModels(user);
125             for (RepositoryModel model : models) {
126                 if (!model.hasCommits) {
127                     // skip empty repository
128                     continue;
129                 }
130                 if (model.isCollectingGarbage) {
131                     // skip garbage collecting repository
132                     logger.warn(MessageFormat.format("Temporarily excluding {0} from RPC, busy collecting garbage",
133                             model.name));
134                     continue;
135                 }
136                 // get local branches
137                 Repository repository = gitblit.getRepository(model.name);
138                 List<RefModel> refs = JGitUtils.getLocalBranches(repository, false, -1);
139                 if (model.showRemoteBranches) {
140                     // add remote branches if repository displays them
141                     refs.addAll(JGitUtils.getRemoteBranches(repository, false, -1));
142                 }
143                 if (refs.size() > 0) {
144                     List<String> branches = new ArrayList<String>();
145                     for (RefModel ref : refs) {
146                         branches.add(ref.getName());
147                     }
148                     localBranches.put(model.name, branches);
149                 }
150                 repository.close();
151             }
152             result = localBranches;
153         } else if (RpcRequest.GET_USER.equals(reqType)) {
154             if (StringUtils.isEmpty(objectName)) {
155                 if (UserModel.ANONYMOUS.equals(user)) {
156                     response.sendError(forbiddenCode);
157                 } else {
158                     // return the current user, reset credentials
159                     UserModel requestedUser = DeepCopier.copy(user);
160                     result = requestedUser;
161                 }
162             } else {
163                 if (user.canAdmin() || objectName.equals(user.username)) {
164                     // return the specified user
165                     UserModel requestedUser = gitblit.getUserModel(objectName);
166                     if (requestedUser == null) {
167                         response.setStatus(failureCode);
168                     } else {
169                         result = requestedUser;
170                     }
171                 } else {
172                     response.sendError(forbiddenCode);
173                 }
174             }
175         } else if (RpcRequest.LIST_USERS.equals(reqType)) {
176             // list users
177             List<String> names = gitblit.getAllUsernames();
178             List<UserModel> users = new ArrayList<UserModel>();
179             for (String name : names) {
180                 users.add(gitblit.getUserModel(name));
181             }
182             result = users;
183         } else if (RpcRequest.LIST_TEAMS.equals(reqType)) {
184             // list teams
185             List<String> names = gitblit.getAllTeamNames();
186             List<TeamModel> teams = new ArrayList<TeamModel>();
187             for (String name : names) {
188                 teams.add(gitblit.getTeamModel(name));
189             }
190             result = teams;
191         } else if (RpcRequest.CREATE_REPOSITORY.equals(reqType)) {
192             // create repository
193             RepositoryModel model = deserialize(request, response, RepositoryModel.class);
194             try {
195                 gitblit.updateRepositoryModel(model.name, model, true);
196             } catch (GitBlitException e) {
197                 response.setStatus(failureCode);
198             }
199         } else if (RpcRequest.FORK_REPOSITORY.equals(reqType)) {
200             // fork repository
201             RepositoryModel origin = gitblit.getRepositoryModel(objectName);
202             if (origin == null) {
203                 // failed to find repository, error is logged by the repository
204                 // manager
205                 response.setStatus(failureCode);
206             } else {
207                 if (user == null || !user.canFork(origin)) {
208                     logger.error("User {} is not permitted to fork '{}'!", user == null ? "anonymous" : user.username,
209                             objectName);
210                     response.setStatus(failureCode);
211                 } else {
212                     try {
213                         // fork the origin
214                         RepositoryModel fork = gitblit.fork(origin, user);
215                         if (fork == null) {
216                             logger.error("Failed to fork repository '{}'!", objectName);
217                             response.setStatus(failureCode);
218                         } else {
219                             logger.info("User {} has forked '{}'!", user.username, objectName);
220                         }
221                     } catch (GitBlitException e) {
222                         response.setStatus(failureCode);
223                     }
224                 }
225             }
226         } else if (RpcRequest.EDIT_REPOSITORY.equals(reqType)) {
227             // edit repository
228             RepositoryModel model = deserialize(request, response, RepositoryModel.class);
229             // name specifies original repository name in event of rename
230             String repoName = objectName;
231             if (repoName == null) {
232                 repoName = model.name;
233             }
234             try {
235                 gitblit.updateRepositoryModel(repoName, model, false);
236             } catch (GitBlitException e) {
237                 response.setStatus(failureCode);
238             }
239         } else if (RpcRequest.DELETE_REPOSITORY.equals(reqType)) {
240             // delete repository
241             RepositoryModel model = deserialize(request, response, RepositoryModel.class);
242             gitblit.deleteRepositoryModel(model);
243         } else if (RpcRequest.CREATE_USER.equals(reqType)) {
244             // create user
245             UserModel model = deserialize(request, response, UserModel.class);
246             try {
247                 gitblit.addUser(model);
248             } catch (GitBlitException e) {
249                 response.setStatus(failureCode);
250             }
251         } else if (RpcRequest.EDIT_USER.equals(reqType)) {
252             // edit user
253             UserModel model = deserialize(request, response, UserModel.class);
254             // name parameter specifies original user name in event of rename
255             String username = objectName;
256             if (username == null) {
257                 username = model.username;
258             }
259             try {
260                 gitblit.reviseUser(username, model);
261             } catch (GitBlitException e) {
262                 response.setStatus(failureCode);
263             }
264         } else if (RpcRequest.DELETE_USER.equals(reqType)) {
265             // delete user
266             UserModel model = deserialize(request, response, UserModel.class);
267             if (!gitblit.deleteUser(model.username)) {
268                 response.setStatus(failureCode);
269             }
270         } else if (RpcRequest.CREATE_TEAM.equals(reqType)) {
271             // create team
272             TeamModel model = deserialize(request, response, TeamModel.class);
273             try {
274                 gitblit.addTeam(model);
275             } catch (GitBlitException e) {
276                 response.setStatus(failureCode);
277             }
278         } else if (RpcRequest.EDIT_TEAM.equals(reqType)) {
279             // edit team
280             TeamModel model = deserialize(request, response, TeamModel.class);
281             // name parameter specifies original team name in event of rename
282             String teamname = objectName;
283             if (teamname == null) {
284                 teamname = model.name;
285             }
286             try {
287                 gitblit.reviseTeam(teamname, model);
288             } catch (GitBlitException e) {
289                 response.setStatus(failureCode);
290             }
291         } else if (RpcRequest.DELETE_TEAM.equals(reqType)) {
292             // delete team
293             TeamModel model = deserialize(request, response, TeamModel.class);
294             if (!gitblit.deleteTeam(model.name)) {
295                 response.setStatus(failureCode);
296             }
297         } else if (RpcRequest.LIST_REPOSITORY_MEMBERS.equals(reqType)) {
298             // get repository members
299             RepositoryModel model = gitblit.getRepositoryModel(objectName);
300             result = gitblit.getRepositoryUsers(model);
301         } else if (RpcRequest.SET_REPOSITORY_MEMBERS.equals(reqType)) {
302             // rejected since 1.2.0
303             response.setStatus(failureCode);
304         } else if (RpcRequest.LIST_REPOSITORY_MEMBER_PERMISSIONS.equals(reqType)) {
305             // get repository member permissions
306             RepositoryModel model = gitblit.getRepositoryModel(objectName);
307             result = gitblit.getUserAccessPermissions(model);
308         } else if (RpcRequest.SET_REPOSITORY_MEMBER_PERMISSIONS.equals(reqType)) {
309             // set the repository permissions for the specified users
310             RepositoryModel model = gitblit.getRepositoryModel(objectName);
311             Collection<RegistrantAccessPermission> permissions = deserialize(request, response,
312                     RpcUtils.REGISTRANT_PERMISSIONS_TYPE);
313             result = gitblit.setUserAccessPermissions(model, permissions);
314         } else if (RpcRequest.LIST_REPOSITORY_TEAMS.equals(reqType)) {
315             // get repository teams
316             RepositoryModel model = gitblit.getRepositoryModel(objectName);
317             result = gitblit.getRepositoryTeams(model);
318         } else if (RpcRequest.SET_REPOSITORY_TEAMS.equals(reqType)) {
319             // rejected since 1.2.0
320             response.setStatus(failureCode);
321         } else if (RpcRequest.LIST_REPOSITORY_TEAM_PERMISSIONS.equals(reqType)) {
322             // get repository team permissions
323             RepositoryModel model = gitblit.getRepositoryModel(objectName);
324             result = gitblit.getTeamAccessPermissions(model);
325         } else if (RpcRequest.SET_REPOSITORY_TEAM_PERMISSIONS.equals(reqType)) {
326             // set the repository permissions for the specified teams
327             RepositoryModel model = gitblit.getRepositoryModel(objectName);
328             Collection<RegistrantAccessPermission> permissions = deserialize(request, response,
329                     RpcUtils.REGISTRANT_PERMISSIONS_TYPE);
330             result = gitblit.setTeamAccessPermissions(model, permissions);
331         } else if (RpcRequest.LIST_FEDERATION_REGISTRATIONS.equals(reqType)) {
332             // return the list of federation registrations
333             if (allowAdmin) {
334                 result = gitblit.getFederationRegistrations();
335             } else {
336                 response.sendError(notAllowedCode);
337             }
338         } else if (RpcRequest.LIST_FEDERATION_RESULTS.equals(reqType)) {
339             // return the list of federation result registrations
340             if (allowAdmin && gitblit.canFederate()) {
341                 result = gitblit.getFederationResultRegistrations();
342             } else {
343                 response.sendError(notAllowedCode);
344             }
345         } else if (RpcRequest.LIST_FEDERATION_PROPOSALS.equals(reqType)) {
346             // return the list of federation proposals
347             if (allowAdmin && gitblit.canFederate()) {
348                 result = gitblit.getPendingFederationProposals();
349             } else {
350                 response.sendError(notAllowedCode);
351             }
352         } else if (RpcRequest.LIST_FEDERATION_SETS.equals(reqType)) {
353             // return the list of federation sets
354             if (allowAdmin && gitblit.canFederate()) {
355                 String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null);
356                 if (StringUtils.isEmpty(gitblitUrl)) {
357                     gitblitUrl = HttpUtils.getGitblitURL(request);
358                 }
359                 result = gitblit.getFederationSets(gitblitUrl);
360             } else {
361                 response.sendError(notAllowedCode);
362             }
363         } else if (RpcRequest.LIST_SETTINGS.equals(reqType)) {
364             // return the server's settings
365             ServerSettings serverSettings = gitblit.getSettingsModel();
366             if (allowAdmin) {
367                 // return all settings
368                 result = serverSettings;
369             } else {
370                 // anonymous users get a few settings to allow browser launching
371                 List<String> keys = new ArrayList<String>();
372                 keys.add(Keys.web.siteName);
373                 keys.add(Keys.web.mountParameters);
374                 keys.add(Keys.web.syndicationEntries);
93f0b1 375
311ae9 376                 if (allowManagement) {
JM 377                     // keys necessary for repository and/or user management
378                     keys.add(Keys.realm.minPasswordLength);
379                     keys.add(Keys.realm.passwordStorage);
380                     keys.add(Keys.federation.sets);
381                 }
382                 // build the settings
383                 ServerSettings managementSettings = new ServerSettings();
384                 for (String key : keys) {
385                     managementSettings.add(serverSettings.get(key));
386                 }
387                 if (allowManagement) {
388                     managementSettings.pushScripts = serverSettings.pushScripts;
389                 }
390                 result = managementSettings;
391             }
392         } else if (RpcRequest.EDIT_SETTINGS.equals(reqType)) {
393             // update settings on the server
394             if (allowAdmin) {
395                 Map<String, String> map = deserialize(request, response, RpcUtils.SETTINGS_TYPE);
396                 gitblit.updateSettings(map);
397             } else {
398                 response.sendError(notAllowedCode);
399             }
400         } else if (RpcRequest.LIST_STATUS.equals(reqType)) {
401             // return the server's status information
402             if (allowAdmin) {
403                 result = gitblit.getStatus();
404             } else {
405                 response.sendError(notAllowedCode);
406             }
407         } else if (RpcRequest.CLEAR_REPOSITORY_CACHE.equals(reqType)) {
408             // clear the repository list cache
409             if (allowManagement) {
410                 gitblit.resetRepositoryListCache();
411             } else {
412                 response.sendError(notAllowedCode);
413             }
414         } else if (RpcRequest.REINDEX_TICKETS.equals(reqType)) {
415             if (allowManagement) {
416                 if (StringUtils.isEmpty(objectName)) {
417                     // reindex all tickets
418                     gitblit.getTicketService().reindex();
419                 } else {
420                     // reindex tickets in a specific repository
421                     RepositoryModel model = gitblit.getRepositoryModel(objectName);
422                     gitblit.getTicketService().reindex(model);
423                 }
424             } else {
425                 response.sendError(notAllowedCode);
426             }
427         }
03d5ee 428
311ae9 429         // send the result of the request
JM 430         serialize(response, result);
431     }
93f0b1 432 }