commit | author | age
|
269c50
|
1 |
/* |
JM |
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.manager; |
|
17 |
|
|
18 |
import java.io.IOException; |
58baee
|
19 |
import java.net.URI; |
269c50
|
20 |
import java.text.MessageFormat; |
7d3a31
|
21 |
import java.util.ArrayList; |
269c50
|
22 |
import java.util.Arrays; |
7d3a31
|
23 |
import java.util.Collections; |
JM |
24 |
import java.util.Comparator; |
269c50
|
25 |
import java.util.Date; |
7d3a31
|
26 |
import java.util.HashSet; |
JM |
27 |
import java.util.Iterator; |
269c50
|
28 |
import java.util.List; |
7d3a31
|
29 |
import java.util.Set; |
269c50
|
30 |
import java.util.concurrent.Executors; |
JM |
31 |
import java.util.concurrent.ScheduledExecutorService; |
|
32 |
import java.util.concurrent.TimeUnit; |
|
33 |
|
3a9e76
|
34 |
import javax.servlet.http.HttpServletRequest; |
JM |
35 |
|
269c50
|
36 |
import org.slf4j.Logger; |
JM |
37 |
import org.slf4j.LoggerFactory; |
|
38 |
|
7d3a31
|
39 |
import com.gitblit.Constants; |
3a9e76
|
40 |
import com.gitblit.Constants.AccessPermission; |
JM |
41 |
import com.gitblit.Constants.AccessRestrictionType; |
269c50
|
42 |
import com.gitblit.Constants.FederationToken; |
7d3a31
|
43 |
import com.gitblit.Constants.Transport; |
269c50
|
44 |
import com.gitblit.IStoredSettings; |
JM |
45 |
import com.gitblit.Keys; |
|
46 |
import com.gitblit.fanout.FanoutNioService; |
|
47 |
import com.gitblit.fanout.FanoutService; |
|
48 |
import com.gitblit.fanout.FanoutSocketService; |
|
49 |
import com.gitblit.models.FederationModel; |
3a9e76
|
50 |
import com.gitblit.models.RepositoryModel; |
7d3a31
|
51 |
import com.gitblit.models.RepositoryUrl; |
3a9e76
|
52 |
import com.gitblit.models.UserModel; |
7bf6e1
|
53 |
import com.gitblit.service.FederationPullService; |
31f477
|
54 |
import com.gitblit.transport.git.GitDaemon; |
41124c
|
55 |
import com.gitblit.transport.ssh.SshDaemon; |
7d3a31
|
56 |
import com.gitblit.utils.HttpUtils; |
269c50
|
57 |
import com.gitblit.utils.StringUtils; |
JM |
58 |
import com.gitblit.utils.TimeUtils; |
5bb55f
|
59 |
import com.gitblit.utils.WorkQueue; |
7d3a31
|
60 |
import com.google.inject.Inject; |
JM |
61 |
import com.google.inject.Provider; |
|
62 |
import com.google.inject.Singleton; |
269c50
|
63 |
|
JM |
64 |
/** |
|
65 |
* Services manager manages long-running services/processes that either have no |
|
66 |
* direct relation to other managers OR require really high-level manager |
|
67 |
* integration (i.e. a Gitblit instance). |
|
68 |
* |
|
69 |
* @author James Moger |
|
70 |
* |
|
71 |
*/ |
7d3a31
|
72 |
@Singleton |
JM |
73 |
public class ServicesManager implements IServicesManager { |
269c50
|
74 |
|
JM |
75 |
private final Logger logger = LoggerFactory.getLogger(getClass()); |
|
76 |
|
|
77 |
private final ScheduledExecutorService scheduledExecutor = Executors.newScheduledThreadPool(5); |
|
78 |
|
7d3a31
|
79 |
private final Provider<WorkQueue> workQueueProvider; |
JM |
80 |
|
269c50
|
81 |
private final IStoredSettings settings; |
JM |
82 |
|
23e08c
|
83 |
private final IGitblit gitblit; |
5bb55f
|
84 |
|
269c50
|
85 |
private FanoutService fanoutService; |
JM |
86 |
|
|
87 |
private GitDaemon gitDaemon; |
|
88 |
|
41124c
|
89 |
private SshDaemon sshDaemon; |
EM |
90 |
|
7d3a31
|
91 |
@Inject |
JM |
92 |
public ServicesManager( |
|
93 |
Provider<WorkQueue> workQueueProvider, |
|
94 |
IStoredSettings settings, |
|
95 |
IGitblit gitblit) { |
|
96 |
|
|
97 |
this.workQueueProvider = workQueueProvider; |
|
98 |
|
|
99 |
this.settings = settings; |
269c50
|
100 |
this.gitblit = gitblit; |
JM |
101 |
} |
|
102 |
|
|
103 |
@Override |
|
104 |
public ServicesManager start() { |
|
105 |
configureFederation(); |
|
106 |
configureFanout(); |
|
107 |
configureGitDaemon(); |
41124c
|
108 |
configureSshDaemon(); |
269c50
|
109 |
|
JM |
110 |
return this; |
|
111 |
} |
|
112 |
|
|
113 |
@Override |
|
114 |
public ServicesManager stop() { |
|
115 |
scheduledExecutor.shutdownNow(); |
|
116 |
if (fanoutService != null) { |
|
117 |
fanoutService.stop(); |
|
118 |
} |
|
119 |
if (gitDaemon != null) { |
|
120 |
gitDaemon.stop(); |
924c9b
|
121 |
} |
JM |
122 |
if (sshDaemon != null) { |
|
123 |
sshDaemon.stop(); |
269c50
|
124 |
} |
7d3a31
|
125 |
workQueueProvider.get().stop(); |
269c50
|
126 |
return this; |
JM |
127 |
} |
|
128 |
|
7d3a31
|
129 |
protected String getRepositoryUrl(HttpServletRequest request, String username, RepositoryModel repository) { |
JM |
130 |
String gitblitUrl = settings.getString(Keys.web.canonicalUrl, null); |
|
131 |
if (StringUtils.isEmpty(gitblitUrl)) { |
|
132 |
gitblitUrl = HttpUtils.getGitblitURL(request); |
|
133 |
} |
|
134 |
StringBuilder sb = new StringBuilder(); |
|
135 |
sb.append(gitblitUrl); |
|
136 |
sb.append(Constants.R_PATH); |
|
137 |
sb.append(repository.name); |
|
138 |
|
|
139 |
// inject username into repository url if authentication is required |
|
140 |
if (repository.accessRestriction.exceeds(AccessRestrictionType.NONE) |
|
141 |
&& !StringUtils.isEmpty(username)) { |
|
142 |
sb.insert(sb.indexOf("://") + 3, username + "@"); |
|
143 |
} |
|
144 |
return sb.toString(); |
|
145 |
} |
|
146 |
|
|
147 |
/** |
|
148 |
* Returns a list of repository URLs and the user access permission. |
|
149 |
* |
|
150 |
* @param request |
|
151 |
* @param user |
|
152 |
* @param repository |
|
153 |
* @return a list of repository urls |
|
154 |
*/ |
|
155 |
@Override |
|
156 |
public List<RepositoryUrl> getRepositoryUrls(HttpServletRequest request, UserModel user, RepositoryModel repository) { |
|
157 |
if (user == null) { |
|
158 |
user = UserModel.ANONYMOUS; |
|
159 |
} |
|
160 |
String username = StringUtils.encodeUsername(UserModel.ANONYMOUS.equals(user) ? "" : user.username); |
|
161 |
|
|
162 |
List<RepositoryUrl> list = new ArrayList<RepositoryUrl>(); |
|
163 |
|
|
164 |
// http/https url |
c20191
|
165 |
if (settings.getBoolean(Keys.git.enableGitServlet, true) && |
JJ |
166 |
settings.getBoolean(Keys.web.showHttpServletUrls, true)) { |
7d3a31
|
167 |
AccessPermission permission = user.getRepositoryPermission(repository).permission; |
JM |
168 |
if (permission.exceeds(AccessPermission.NONE)) { |
2db6b3
|
169 |
String repoUrl = getRepositoryUrl(request, username, repository); |
JJ |
170 |
Transport transport = Transport.fromUrl(repoUrl); |
67ba8f
|
171 |
if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(transport)) { |
7d3a31
|
172 |
// downgrade the repo permission for this transport |
JM |
173 |
// because it is not an acceptable PUSH transport |
|
174 |
permission = AccessPermission.CLONE; |
|
175 |
} |
2db6b3
|
176 |
list.add(new RepositoryUrl(repoUrl, permission)); |
7d3a31
|
177 |
} |
JM |
178 |
} |
|
179 |
|
|
180 |
// ssh daemon url |
|
181 |
String sshDaemonUrl = getSshDaemonUrl(request, user, repository); |
c20191
|
182 |
if (!StringUtils.isEmpty(sshDaemonUrl) && |
JJ |
183 |
settings.getBoolean(Keys.web.showSshDaemonUrls, true)) { |
7d3a31
|
184 |
AccessPermission permission = user.getRepositoryPermission(repository).permission; |
JM |
185 |
if (permission.exceeds(AccessPermission.NONE)) { |
67ba8f
|
186 |
if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(Transport.SSH)) { |
7d3a31
|
187 |
// downgrade the repo permission for this transport |
JM |
188 |
// because it is not an acceptable PUSH transport |
|
189 |
permission = AccessPermission.CLONE; |
|
190 |
} |
|
191 |
|
|
192 |
list.add(new RepositoryUrl(sshDaemonUrl, permission)); |
|
193 |
} |
|
194 |
} |
|
195 |
|
|
196 |
// git daemon url |
|
197 |
String gitDaemonUrl = getGitDaemonUrl(request, user, repository); |
c20191
|
198 |
if (!StringUtils.isEmpty(gitDaemonUrl) && |
JJ |
199 |
settings.getBoolean(Keys.web.showGitDaemonUrls, true)) { |
7d3a31
|
200 |
AccessPermission permission = getGitDaemonAccessPermission(user, repository); |
JM |
201 |
if (permission.exceeds(AccessPermission.NONE)) { |
67ba8f
|
202 |
if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(Transport.GIT)) { |
7d3a31
|
203 |
// downgrade the repo permission for this transport |
JM |
204 |
// because it is not an acceptable PUSH transport |
|
205 |
permission = AccessPermission.CLONE; |
|
206 |
} |
|
207 |
list.add(new RepositoryUrl(gitDaemonUrl, permission)); |
|
208 |
} |
|
209 |
} |
|
210 |
|
|
211 |
// add all other urls |
|
212 |
// {0} = repository |
|
213 |
// {1} = username |
1590fd
|
214 |
boolean advertisePermsForOther = settings.getBoolean(Keys.web.advertiseAccessPermissionForOtherUrls, false); |
7d3a31
|
215 |
for (String url : settings.getStrings(Keys.web.otherUrls)) { |
1590fd
|
216 |
String externalUrl = null; |
JJ |
217 |
|
7d3a31
|
218 |
if (url.contains("{1}")) { |
JM |
219 |
// external url requires username, only add url IF we have one |
1590fd
|
220 |
if (StringUtils.isEmpty(username)) { |
JJ |
221 |
continue; |
|
222 |
} else { |
|
223 |
externalUrl = MessageFormat.format(url, repository.name, username); |
7d3a31
|
224 |
} |
JM |
225 |
} else { |
1590fd
|
226 |
// external url does not require username, just do repo name formatting |
JJ |
227 |
externalUrl = MessageFormat.format(url, repository.name); |
7d3a31
|
228 |
} |
1590fd
|
229 |
|
JJ |
230 |
AccessPermission permission = null; |
|
231 |
if (advertisePermsForOther) { |
|
232 |
permission = user.getRepositoryPermission(repository).permission; |
|
233 |
if (permission.exceeds(AccessPermission.NONE)) { |
|
234 |
Transport transport = Transport.fromUrl(externalUrl); |
|
235 |
if (permission.atLeast(AccessPermission.PUSH) && !acceptsPush(transport)) { |
|
236 |
// downgrade the repo permission for this transport |
|
237 |
// because it is not an acceptable PUSH transport |
|
238 |
permission = AccessPermission.CLONE; |
|
239 |
} |
|
240 |
} |
|
241 |
} |
|
242 |
list.add(new RepositoryUrl(externalUrl, permission)); |
7d3a31
|
243 |
} |
JM |
244 |
|
|
245 |
// sort transports by highest permission and then by transport security |
|
246 |
Collections.sort(list, new Comparator<RepositoryUrl>() { |
|
247 |
|
|
248 |
@Override |
|
249 |
public int compare(RepositoryUrl o1, RepositoryUrl o2) { |
1590fd
|
250 |
if (o1.hasPermission() && !o2.hasPermission()) { |
JJ |
251 |
// prefer known permission items over unknown |
7d3a31
|
252 |
return -1; |
1590fd
|
253 |
} else if (!o1.hasPermission() && o2.hasPermission()) { |
JJ |
254 |
// prefer known permission items over unknown |
7d3a31
|
255 |
return 1; |
1590fd
|
256 |
} else if (!o1.hasPermission() && !o2.hasPermission()) { |
7d3a31
|
257 |
// sort by Transport ordinal |
JM |
258 |
return o1.transport.compareTo(o2.transport); |
|
259 |
} else if (o1.permission.exceeds(o2.permission)) { |
|
260 |
// prefer highest permission |
|
261 |
return -1; |
|
262 |
} else if (o2.permission.exceeds(o1.permission)) { |
|
263 |
// prefer highest permission |
|
264 |
return 1; |
|
265 |
} |
|
266 |
|
|
267 |
// prefer more secure transports |
|
268 |
return o1.transport.compareTo(o2.transport); |
|
269 |
} |
|
270 |
}); |
|
271 |
|
|
272 |
// consider the user's transport preference |
|
273 |
RepositoryUrl preferredUrl = null; |
|
274 |
Transport preferredTransport = user.getPreferences().getTransport(); |
|
275 |
if (preferredTransport != null) { |
|
276 |
Iterator<RepositoryUrl> itr = list.iterator(); |
|
277 |
while (itr.hasNext()) { |
|
278 |
RepositoryUrl url = itr.next(); |
|
279 |
if (url.transport.equals(preferredTransport)) { |
|
280 |
itr.remove(); |
|
281 |
preferredUrl = url; |
|
282 |
break; |
|
283 |
} |
|
284 |
} |
|
285 |
} |
|
286 |
if (preferredUrl != null) { |
|
287 |
list.add(0, preferredUrl); |
|
288 |
} |
|
289 |
|
|
290 |
return list; |
|
291 |
} |
|
292 |
|
|
293 |
/* (non-Javadoc) |
|
294 |
* @see com.gitblit.manager.IServicesManager#isServingRepositories() |
|
295 |
*/ |
|
296 |
@Override |
8b8799
|
297 |
public boolean isServingRepositories() { |
67ba8f
|
298 |
return isServingHTTPS() |
JM |
299 |
|| isServingHTTP() |
05f229
|
300 |
|| isServingGIT() |
JM |
301 |
|| isServingSSH(); |
|
302 |
} |
|
303 |
|
7d3a31
|
304 |
/* (non-Javadoc) |
JM |
305 |
* @see com.gitblit.manager.IServicesManager#isServingHTTP() |
|
306 |
*/ |
|
307 |
@Override |
05f229
|
308 |
public boolean isServingHTTP() { |
67ba8f
|
309 |
return settings.getBoolean(Keys.git.enableGitServlet, true) |
JM |
310 |
&& ((gitblit.getStatus().isGO && settings.getInteger(Keys.server.httpPort, 0) > 0) |
|
311 |
|| !gitblit.getStatus().isGO); |
|
312 |
} |
|
313 |
|
|
314 |
/* (non-Javadoc) |
|
315 |
* @see com.gitblit.manager.IServicesManager#isServingHTTPS() |
|
316 |
*/ |
|
317 |
@Override |
|
318 |
public boolean isServingHTTPS() { |
|
319 |
return settings.getBoolean(Keys.git.enableGitServlet, true) |
|
320 |
&& ((gitblit.getStatus().isGO && settings.getInteger(Keys.server.httpsPort, 0) > 0) |
|
321 |
|| !gitblit.getStatus().isGO); |
05f229
|
322 |
} |
JM |
323 |
|
7d3a31
|
324 |
/* (non-Javadoc) |
JM |
325 |
* @see com.gitblit.manager.IServicesManager#isServingGIT() |
|
326 |
*/ |
|
327 |
@Override |
05f229
|
328 |
public boolean isServingGIT() { |
JM |
329 |
return gitDaemon != null && gitDaemon.isRunning(); |
|
330 |
} |
|
331 |
|
7d3a31
|
332 |
/* (non-Javadoc) |
JM |
333 |
* @see com.gitblit.manager.IServicesManager#isServingSSH() |
|
334 |
*/ |
|
335 |
@Override |
05f229
|
336 |
public boolean isServingSSH() { |
JM |
337 |
return sshDaemon != null && sshDaemon.isRunning(); |
8b8799
|
338 |
} |
JM |
339 |
|
269c50
|
340 |
protected void configureFederation() { |
JM |
341 |
boolean validPassphrase = true; |
|
342 |
String passphrase = settings.getString(Keys.federation.passphrase, ""); |
|
343 |
if (StringUtils.isEmpty(passphrase)) { |
|
344 |
logger.info("Federation passphrase is blank! This server can not be PULLED from."); |
|
345 |
validPassphrase = false; |
|
346 |
} |
|
347 |
if (validPassphrase) { |
|
348 |
// standard tokens |
|
349 |
for (FederationToken tokenType : FederationToken.values()) { |
|
350 |
logger.info(MessageFormat.format("Federation {0} token = {1}", tokenType.name(), |
|
351 |
gitblit.getFederationToken(tokenType))); |
|
352 |
} |
|
353 |
|
|
354 |
// federation set tokens |
|
355 |
for (String set : settings.getStrings(Keys.federation.sets)) { |
|
356 |
logger.info(MessageFormat.format("Federation Set {0} token = {1}", set, |
|
357 |
gitblit.getFederationToken(set))); |
|
358 |
} |
|
359 |
} |
|
360 |
|
|
361 |
// Schedule or run the federation executor |
|
362 |
List<FederationModel> registrations = gitblit.getFederationRegistrations(); |
|
363 |
if (registrations.size() > 0) { |
|
364 |
FederationPuller executor = new FederationPuller(registrations); |
|
365 |
scheduledExecutor.schedule(executor, 1, TimeUnit.MINUTES); |
|
366 |
} |
|
367 |
} |
|
368 |
|
67ba8f
|
369 |
@Override |
JM |
370 |
public boolean acceptsPush(Transport byTransport) { |
7d3a31
|
371 |
if (byTransport == null) { |
JM |
372 |
logger.info("Unknown transport, push rejected!"); |
|
373 |
return false; |
|
374 |
} |
|
375 |
|
|
376 |
Set<Transport> transports = new HashSet<Transport>(); |
|
377 |
for (String value : settings.getStrings(Keys.git.acceptedPushTransports)) { |
|
378 |
Transport transport = Transport.fromString(value); |
|
379 |
if (transport == null) { |
|
380 |
logger.info(String.format("Ignoring unknown registered transport %s", value)); |
|
381 |
continue; |
|
382 |
} |
|
383 |
|
|
384 |
transports.add(transport); |
|
385 |
} |
|
386 |
|
|
387 |
if (transports.isEmpty()) { |
|
388 |
// no transports are explicitly specified, all are acceptable |
|
389 |
return true; |
|
390 |
} |
|
391 |
|
|
392 |
// verify that the transport is permitted |
|
393 |
return transports.contains(byTransport); |
|
394 |
} |
|
395 |
|
269c50
|
396 |
protected void configureGitDaemon() { |
JM |
397 |
int port = settings.getInteger(Keys.git.daemonPort, 0); |
|
398 |
String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost"); |
|
399 |
if (port > 0) { |
|
400 |
try { |
|
401 |
gitDaemon = new GitDaemon(gitblit); |
|
402 |
gitDaemon.start(); |
|
403 |
} catch (IOException e) { |
|
404 |
gitDaemon = null; |
|
405 |
logger.error(MessageFormat.format("Failed to start Git Daemon on {0}:{1,number,0}", bindInterface, port), e); |
|
406 |
} |
|
407 |
} else { |
|
408 |
logger.info("Git Daemon is disabled."); |
|
409 |
} |
|
410 |
} |
|
411 |
|
41124c
|
412 |
protected void configureSshDaemon() { |
EM |
413 |
int port = settings.getInteger(Keys.git.sshPort, 0); |
|
414 |
String bindInterface = settings.getString(Keys.git.sshBindInterface, "localhost"); |
|
415 |
if (port > 0) { |
|
416 |
try { |
7d3a31
|
417 |
sshDaemon = new SshDaemon(gitblit, workQueueProvider.get()); |
41124c
|
418 |
sshDaemon.start(); |
EM |
419 |
} catch (IOException e) { |
|
420 |
sshDaemon = null; |
|
421 |
logger.error(MessageFormat.format("Failed to start SSH daemon on {0}:{1,number,0}", bindInterface, port), e); |
|
422 |
} |
|
423 |
} |
|
424 |
} |
|
425 |
|
269c50
|
426 |
protected void configureFanout() { |
JM |
427 |
// startup Fanout PubSub service |
|
428 |
if (settings.getInteger(Keys.fanout.port, 0) > 0) { |
|
429 |
String bindInterface = settings.getString(Keys.fanout.bindInterface, null); |
|
430 |
int port = settings.getInteger(Keys.fanout.port, FanoutService.DEFAULT_PORT); |
|
431 |
boolean useNio = settings.getBoolean(Keys.fanout.useNio, true); |
|
432 |
int limit = settings.getInteger(Keys.fanout.connectionLimit, 0); |
|
433 |
|
|
434 |
if (useNio) { |
|
435 |
if (StringUtils.isEmpty(bindInterface)) { |
|
436 |
fanoutService = new FanoutNioService(port); |
|
437 |
} else { |
|
438 |
fanoutService = new FanoutNioService(bindInterface, port); |
|
439 |
} |
|
440 |
} else { |
|
441 |
if (StringUtils.isEmpty(bindInterface)) { |
|
442 |
fanoutService = new FanoutSocketService(port); |
|
443 |
} else { |
|
444 |
fanoutService = new FanoutSocketService(bindInterface, port); |
|
445 |
} |
|
446 |
} |
|
447 |
|
|
448 |
fanoutService.setConcurrentConnectionLimit(limit); |
|
449 |
fanoutService.setAllowAllChannelAnnouncements(false); |
|
450 |
fanoutService.start(); |
|
451 |
} else { |
|
452 |
logger.info("Fanout PubSub service is disabled."); |
|
453 |
} |
|
454 |
} |
|
455 |
|
3a9e76
|
456 |
public String getGitDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) { |
JM |
457 |
if (gitDaemon != null) { |
|
458 |
String bindInterface = settings.getString(Keys.git.daemonBindInterface, "localhost"); |
|
459 |
if (bindInterface.equals("localhost") |
|
460 |
&& (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) { |
|
461 |
// git daemon is bound to localhost and the request is from elsewhere |
|
462 |
return null; |
|
463 |
} |
|
464 |
if (user.canClone(repository)) { |
58baee
|
465 |
String hostname = getHostname(request); |
JM |
466 |
String url = gitDaemon.formatUrl(hostname, repository.name); |
3a9e76
|
467 |
return url; |
JM |
468 |
} |
|
469 |
} |
|
470 |
return null; |
|
471 |
} |
|
472 |
|
|
473 |
public AccessPermission getGitDaemonAccessPermission(UserModel user, RepositoryModel repository) { |
|
474 |
if (gitDaemon != null && user.canClone(repository)) { |
|
475 |
AccessPermission gitDaemonPermission = user.getRepositoryPermission(repository).permission; |
|
476 |
if (gitDaemonPermission.atLeast(AccessPermission.CLONE)) { |
|
477 |
if (repository.accessRestriction.atLeast(AccessRestrictionType.CLONE)) { |
|
478 |
// can not authenticate clone via anonymous git protocol |
|
479 |
gitDaemonPermission = AccessPermission.NONE; |
|
480 |
} else if (repository.accessRestriction.atLeast(AccessRestrictionType.PUSH)) { |
|
481 |
// can not authenticate push via anonymous git protocol |
|
482 |
gitDaemonPermission = AccessPermission.CLONE; |
|
483 |
} else { |
|
484 |
// normal user permission |
|
485 |
} |
|
486 |
} |
|
487 |
return gitDaemonPermission; |
|
488 |
} |
|
489 |
return AccessPermission.NONE; |
|
490 |
} |
|
491 |
|
58baee
|
492 |
public String getSshDaemonUrl(HttpServletRequest request, UserModel user, RepositoryModel repository) { |
13331a
|
493 |
if (user == null || UserModel.ANONYMOUS.equals(user)) { |
JM |
494 |
// SSH always requires authentication - anonymous access prohibited |
|
495 |
return null; |
|
496 |
} |
58baee
|
497 |
if (sshDaemon != null) { |
JM |
498 |
String bindInterface = settings.getString(Keys.git.sshBindInterface, "localhost"); |
|
499 |
if (bindInterface.equals("localhost") |
|
500 |
&& (!request.getServerName().equals("localhost") && !request.getServerName().equals("127.0.0.1"))) { |
|
501 |
// ssh daemon is bound to localhost and the request is from elsewhere |
|
502 |
return null; |
|
503 |
} |
|
504 |
if (user.canClone(repository)) { |
|
505 |
String hostname = getHostname(request); |
|
506 |
String url = sshDaemon.formatUrl(user.username, hostname, repository.name); |
|
507 |
return url; |
|
508 |
} |
|
509 |
} |
|
510 |
return null; |
|
511 |
} |
|
512 |
|
d5603a
|
513 |
|
58baee
|
514 |
/** |
JM |
515 |
* Extract the hostname from the canonical url or return the |
|
516 |
* hostname from the servlet request. |
d5603a
|
517 |
* |
58baee
|
518 |
* @param request |
JM |
519 |
* @return |
|
520 |
*/ |
|
521 |
protected String getHostname(HttpServletRequest request) { |
|
522 |
String hostname = request.getServerName(); |
7d3a31
|
523 |
String canonicalUrl = settings.getString(Keys.web.canonicalUrl, null); |
58baee
|
524 |
if (!StringUtils.isEmpty(canonicalUrl)) { |
JM |
525 |
try { |
|
526 |
URI uri = new URI(canonicalUrl); |
|
527 |
String host = uri.getHost(); |
|
528 |
if (!StringUtils.isEmpty(host) && !"localhost".equals(host)) { |
|
529 |
hostname = host; |
|
530 |
} |
|
531 |
} catch (Exception e) { |
|
532 |
} |
|
533 |
} |
|
534 |
return hostname; |
|
535 |
} |
3a9e76
|
536 |
|
7bf6e1
|
537 |
private class FederationPuller extends FederationPullService { |
269c50
|
538 |
|
JM |
539 |
public FederationPuller(FederationModel registration) { |
23e08c
|
540 |
super(gitblit, Arrays.asList(registration)); |
269c50
|
541 |
} |
JM |
542 |
|
|
543 |
public FederationPuller(List<FederationModel> registrations) { |
23e08c
|
544 |
super(gitblit, registrations); |
269c50
|
545 |
} |
JM |
546 |
|
|
547 |
@Override |
|
548 |
public void reschedule(FederationModel registration) { |
|
549 |
// schedule the next pull |
936af6
|
550 |
int mins = TimeUtils.convertFrequencyToMinutes(registration.frequency, 5); |
269c50
|
551 |
registration.nextPull = new Date(System.currentTimeMillis() + (mins * 60 * 1000L)); |
JM |
552 |
scheduledExecutor.schedule(new FederationPuller(registration), mins, TimeUnit.MINUTES); |
|
553 |
logger.info(MessageFormat.format( |
|
554 |
"Next pull of {0} @ {1} scheduled for {2,date,yyyy-MM-dd HH:mm}", |
|
555 |
registration.name, registration.url, registration.nextPull)); |
|
556 |
} |
|
557 |
} |
|
558 |
} |