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.

GitBlit.java 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466
  1. /*
  2. * Copyright 2013 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.text.MessageFormat;
  18. import java.util.ArrayList;
  19. import java.util.Collections;
  20. import java.util.Comparator;
  21. import java.util.HashSet;
  22. import java.util.List;
  23. import java.util.Set;
  24. import javax.inject.Singleton;
  25. import javax.servlet.http.HttpServletRequest;
  26. import com.gitblit.Constants.AccessPermission;
  27. import com.gitblit.Constants.Transport;
  28. import com.gitblit.manager.GitblitManager;
  29. import com.gitblit.manager.IAuthenticationManager;
  30. import com.gitblit.manager.IFederationManager;
  31. import com.gitblit.manager.IGitblit;
  32. import com.gitblit.manager.INotificationManager;
  33. import com.gitblit.manager.IPluginManager;
  34. import com.gitblit.manager.IProjectManager;
  35. import com.gitblit.manager.IRepositoryManager;
  36. import com.gitblit.manager.IRuntimeManager;
  37. import com.gitblit.manager.IUserManager;
  38. import com.gitblit.manager.ServicesManager;
  39. import com.gitblit.models.RepositoryModel;
  40. import com.gitblit.models.RepositoryUrl;
  41. import com.gitblit.models.UserModel;
  42. import com.gitblit.tickets.BranchTicketService;
  43. import com.gitblit.tickets.FileTicketService;
  44. import com.gitblit.tickets.ITicketService;
  45. import com.gitblit.tickets.NullTicketService;
  46. import com.gitblit.tickets.RedisTicketService;
  47. import com.gitblit.transport.ssh.IPublicKeyManager;
  48. import com.gitblit.utils.StringUtils;
  49. import dagger.Module;
  50. import dagger.ObjectGraph;
  51. import dagger.Provides;
  52. /**
  53. * GitBlit is the aggregate manager for the Gitblit webapp. It provides all
  54. * management functions and also manages some long-running services.
  55. *
  56. * @author James Moger
  57. *
  58. */
  59. public class GitBlit extends GitblitManager {
  60. private final ObjectGraph injector;
  61. private final ServicesManager servicesManager;
  62. private ITicketService ticketService;
  63. public GitBlit(
  64. IRuntimeManager runtimeManager,
  65. IPluginManager pluginManager,
  66. INotificationManager notificationManager,
  67. IUserManager userManager,
  68. IAuthenticationManager authenticationManager,
  69. IPublicKeyManager publicKeyManager,
  70. IRepositoryManager repositoryManager,
  71. IProjectManager projectManager,
  72. IFederationManager federationManager) {
  73. super(runtimeManager,
  74. pluginManager,
  75. notificationManager,
  76. userManager,
  77. authenticationManager,
  78. publicKeyManager,
  79. repositoryManager,
  80. projectManager,
  81. federationManager);
  82. this.injector = ObjectGraph.create(getModules());
  83. this.servicesManager = new ServicesManager(this);
  84. }
  85. @Override
  86. public GitBlit start() {
  87. super.start();
  88. logger.info("Starting services manager...");
  89. servicesManager.start();
  90. configureTicketService();
  91. return this;
  92. }
  93. @Override
  94. public GitBlit stop() {
  95. super.stop();
  96. servicesManager.stop();
  97. ticketService.stop();
  98. return this;
  99. }
  100. @Override
  101. public boolean isServingRepositories() {
  102. return servicesManager.isServingRepositories();
  103. }
  104. @Override
  105. public boolean isServingHTTP() {
  106. return servicesManager.isServingHTTP();
  107. }
  108. @Override
  109. public boolean isServingGIT() {
  110. return servicesManager.isServingGIT();
  111. }
  112. @Override
  113. public boolean isServingSSH() {
  114. return servicesManager.isServingSSH();
  115. }
  116. protected Object [] getModules() {
  117. return new Object [] { new GitBlitModule()};
  118. }
  119. protected boolean acceptPush(Transport byTransport) {
  120. if (byTransport == null) {
  121. logger.info("Unknown transport, push rejected!");
  122. return false;
  123. }
  124. Set<Transport> transports = new HashSet<Transport>();
  125. for (String value : getSettings().getStrings(Keys.git.acceptedPushTransports)) {
  126. Transport transport = Transport.fromString(value);
  127. if (transport == null) {
  128. logger.info(String.format("Ignoring unknown registered transport %s", value));
  129. continue;
  130. }
  131. transports.add(transport);
  132. }
  133. if (transports.isEmpty()) {
  134. // no transports are explicitly specified, all are acceptable
  135. return true;
  136. }
  137. // verify that the transport is permitted
  138. return transports.contains(byTransport);
  139. }
  140. /**
  141. * Returns a list of repository URLs and the user access permission.
  142. *
  143. * @param request
  144. * @param user
  145. * @param repository
  146. * @return a list of repository urls
  147. */
  148. @Override
  149. public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) {
  150. if (user == null) {
  151. user = UserModel.ANONYMOUS;
  152. }
  153. String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username);
  154. List<RepositoryUrl> list = new ArrayList<RepositoryUrl>();
  155. // http/https url
  156. if (settings.getBoolean(Keys.git.enableGitServlet, true)) {
  157. AccessPermission permission = user.getRepositoryPermission(repository).permission;
  158. if (permission.exceeds(AccessPermission.NONE)) {
  159. Transport transport = Transport.fromString(request.getScheme());
  160. if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(transport)) {
  161. // downgrade the repo permission for this transport
  162. // because it is not an acceptable PUSH transport
  163. permission = AccessPermission.CLONE;
  164. }
  165. list.add(new RepositoryUrl(getRepositoryUrl(request, username, repository), permission));
  166. }
  167. }
  168. // ssh daemon url
  169. String sshDaemonUrl = servicesManager.getSshDaemonUrl(request, user, repository);
  170. if (!StringUtils.isEmpty(sshDaemonUrl)) {
  171. AccessPermission permission = user.getRepositoryPermission(repository).permission;
  172. if (permission.exceeds(AccessPermission.NONE)) {
  173. if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.SSH)) {
  174. // downgrade the repo permission for this transport
  175. // because it is not an acceptable PUSH transport
  176. permission = AccessPermission.CLONE;
  177. }
  178. list.add(new RepositoryUrl(sshDaemonUrl, permission));
  179. }
  180. }
  181. // git daemon url
  182. String gitDaemonUrl = servicesManager.getGitDaemonUrl(request, user, repository);
  183. if (!StringUtils.isEmpty(gitDaemonUrl)) {
  184. AccessPermission permission = servicesManager.getGitDaemonAccessPermission(user, repository);
  185. if (permission.exceeds(AccessPermission.NONE)) {
  186. if (permission.atLeast(AccessPermission.PUSH) && !acceptPush(Transport.GIT)) {
  187. // downgrade the repo permission for this transport
  188. // because it is not an acceptable PUSH transport
  189. permission = AccessPermission.CLONE;
  190. }
  191. list.add(new RepositoryUrl(gitDaemonUrl, permission));
  192. }
  193. }
  194. // add all other urls
  195. // {0} = repository
  196. // {1} = username
  197. for (String url : settings.getStrings(Keys.web.otherUrls)) {
  198. if (url.contains("{1}")) {
  199. // external url requires username, only add url IF we have one
  200. if (!StringUtils.isEmpty(username)) {
  201. list.add(new RepositoryUrl(MessageFormat.format(url, repository.name, username), null));
  202. }
  203. } else {
  204. // external url does not require username
  205. list.add(new RepositoryUrl(MessageFormat.format(url, repository.name), null));
  206. }
  207. }
  208. // sort transports by highest permission and then by transport security
  209. Collections.sort(list, new Comparator<RepositoryUrl>() {
  210. @Override
  211. public int compare(RepositoryUrl o1, RepositoryUrl o2) {
  212. if (!o1.isExternal() && o2.isExternal()) {
  213. // prefer Gitblit over external
  214. return -1;
  215. } else if (o1.isExternal() && !o2.isExternal()) {
  216. // prefer Gitblit over external
  217. return 1;
  218. } else if (o1.isExternal() && o2.isExternal()) {
  219. // sort by Transport ordinal
  220. return o1.transport.compareTo(o2.transport);
  221. } else if (o1.permission.exceeds(o2.permission)) {
  222. // prefer highest permission
  223. return -1;
  224. } else if (o2.permission.exceeds(o1.permission)) {
  225. // prefer highest permission
  226. return 1;
  227. }
  228. // prefer more secure transports
  229. return o1.transport.compareTo(o2.transport);
  230. }
  231. });
  232. return list;
  233. }
  234. /**
  235. * Detect renames and reindex as appropriate.
  236. */
  237. @Override
  238. public void updateRepositoryModel(String repositoryName, RepositoryModel repository,
  239. boolean isCreate) throws GitBlitException {
  240. RepositoryModel oldModel = null;
  241. boolean isRename = !isCreate && !repositoryName.equalsIgnoreCase(repository.name);
  242. if (isRename) {
  243. oldModel = repositoryManager.getRepositoryModel(repositoryName);
  244. }
  245. super.updateRepositoryModel(repositoryName, repository, isCreate);
  246. if (isRename && ticketService != null) {
  247. ticketService.rename(oldModel, repository);
  248. }
  249. }
  250. /**
  251. * Delete the user and all associated public ssh keys.
  252. */
  253. @Override
  254. public boolean deleteUser(String username) {
  255. UserModel user = userManager.getUserModel(username);
  256. return deleteUserModel(user);
  257. }
  258. @Override
  259. public boolean deleteUserModel(UserModel model) {
  260. boolean success = userManager.deleteUserModel(model);
  261. if (success) {
  262. getPublicKeyManager().removeAllKeys(model.username);
  263. }
  264. return success;
  265. }
  266. /**
  267. * Delete the repository and all associated tickets.
  268. */
  269. @Override
  270. public boolean deleteRepository(String repositoryName) {
  271. RepositoryModel repository = repositoryManager.getRepositoryModel(repositoryName);
  272. return deleteRepositoryModel(repository);
  273. }
  274. @Override
  275. public boolean deleteRepositoryModel(RepositoryModel model) {
  276. boolean success = repositoryManager.deleteRepositoryModel(model);
  277. if (success && ticketService != null) {
  278. ticketService.deleteAll(model);
  279. }
  280. return success;
  281. }
  282. /**
  283. * Returns the configured ticket service.
  284. *
  285. * @return a ticket service
  286. */
  287. @Override
  288. public ITicketService getTicketService() {
  289. return ticketService;
  290. }
  291. protected void configureTicketService() {
  292. String clazz = settings.getString(Keys.tickets.service, NullTicketService.class.getName());
  293. if (StringUtils.isEmpty(clazz)) {
  294. clazz = NullTicketService.class.getName();
  295. }
  296. try {
  297. Class<? extends ITicketService> serviceClass = (Class<? extends ITicketService>) Class.forName(clazz);
  298. ticketService = injector.get(serviceClass).start();
  299. if (ticketService instanceof NullTicketService) {
  300. logger.warn("No ticket service configured.");
  301. } else if (ticketService.isReady()) {
  302. logger.info("{} is ready.", ticketService);
  303. } else {
  304. logger.warn("{} is disabled.", ticketService);
  305. }
  306. } catch (Exception e) {
  307. logger.error("failed to create ticket service " + clazz, e);
  308. ticketService = injector.get(NullTicketService.class).start();
  309. }
  310. }
  311. /**
  312. * A nested Dagger graph is used for constructor dependency injection of
  313. * complex classes.
  314. *
  315. * @author James Moger
  316. *
  317. */
  318. @Module(
  319. library = true,
  320. injects = {
  321. IStoredSettings.class,
  322. // core managers
  323. IRuntimeManager.class,
  324. IPluginManager.class,
  325. INotificationManager.class,
  326. IUserManager.class,
  327. IAuthenticationManager.class,
  328. IRepositoryManager.class,
  329. IProjectManager.class,
  330. IFederationManager.class,
  331. // the monolithic manager
  332. IGitblit.class,
  333. // ticket services
  334. NullTicketService.class,
  335. FileTicketService.class,
  336. BranchTicketService.class,
  337. RedisTicketService.class
  338. }
  339. )
  340. class GitBlitModule {
  341. @Provides @Singleton IStoredSettings provideSettings() {
  342. return settings;
  343. }
  344. @Provides @Singleton IRuntimeManager provideRuntimeManager() {
  345. return runtimeManager;
  346. }
  347. @Provides @Singleton IPluginManager providePluginManager() {
  348. return pluginManager;
  349. }
  350. @Provides @Singleton INotificationManager provideNotificationManager() {
  351. return notificationManager;
  352. }
  353. @Provides @Singleton IUserManager provideUserManager() {
  354. return userManager;
  355. }
  356. @Provides @Singleton IAuthenticationManager provideAuthenticationManager() {
  357. return authenticationManager;
  358. }
  359. @Provides @Singleton IRepositoryManager provideRepositoryManager() {
  360. return repositoryManager;
  361. }
  362. @Provides @Singleton IProjectManager provideProjectManager() {
  363. return projectManager;
  364. }
  365. @Provides @Singleton IFederationManager provideFederationManager() {
  366. return federationManager;
  367. }
  368. @Provides @Singleton IGitblit provideGitblit() {
  369. return GitBlit.this;
  370. }
  371. @Provides @Singleton NullTicketService provideNullTicketService() {
  372. return new NullTicketService(
  373. runtimeManager,
  374. pluginManager,
  375. notificationManager,
  376. userManager,
  377. repositoryManager);
  378. }
  379. @Provides @Singleton FileTicketService provideFileTicketService() {
  380. return new FileTicketService(
  381. runtimeManager,
  382. pluginManager,
  383. notificationManager,
  384. userManager,
  385. repositoryManager);
  386. }
  387. @Provides @Singleton BranchTicketService provideBranchTicketService() {
  388. return new BranchTicketService(
  389. runtimeManager,
  390. pluginManager,
  391. notificationManager,
  392. userManager,
  393. repositoryManager);
  394. }
  395. @Provides @Singleton RedisTicketService provideRedisTicketService() {
  396. return new RedisTicketService(
  397. runtimeManager,
  398. pluginManager,
  399. notificationManager,
  400. userManager,
  401. repositoryManager);
  402. }
  403. }
  404. }