You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

RpcServlet.java 15KB

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