mirror of
https://github.com/theonedev/onedev.git
synced 2025-12-08 18:26:30 +00:00
Send git error messages to git client. Disable session creation for git
operation.
This commit is contained in:
parent
ff4dd0b7cf
commit
4e10bbc1b6
@ -12,6 +12,8 @@ import javax.servlet.http.HttpServletRequest;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
|
import org.apache.shiro.authc.IncorrectCredentialsException;
|
||||||
|
import org.apache.shiro.authc.UnknownAccountException;
|
||||||
import org.apache.shiro.authc.UsernamePasswordToken;
|
import org.apache.shiro.authc.UsernamePasswordToken;
|
||||||
import org.apache.shiro.authz.UnauthenticatedException;
|
import org.apache.shiro.authz.UnauthenticatedException;
|
||||||
import org.apache.shiro.authz.UnauthorizedException;
|
import org.apache.shiro.authz.UnauthorizedException;
|
||||||
@ -73,31 +75,30 @@ public class BasicAuthenticationFilter extends PathMatchingFilter {
|
|||||||
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing)
|
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing)
|
||||||
throws ServletException, IOException {
|
throws ServletException, IOException {
|
||||||
|
|
||||||
boolean sendChallenge = false;
|
HttpServletResponse httpResponse = WebUtils.toHttp(response);
|
||||||
if (existing != null) {
|
if (existing != null) {
|
||||||
if (ExceptionUtils.find(existing, UnauthenticatedException.class) != null) {
|
if (ExceptionUtils.find(existing, UnauthenticatedException.class) != null) {
|
||||||
sendChallenge = true;
|
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
String authcHeader = HttpServletRequest.BASIC_AUTH + " realm=\"" + appName + "\"";
|
||||||
|
httpResponse.setHeader(AUTHENTICATE_HEADER, authcHeader);
|
||||||
|
existing = null;
|
||||||
} else if (ExceptionUtils.find(existing, UnauthorizedException.class) != null) {
|
} else if (ExceptionUtils.find(existing, UnauthorizedException.class) != null) {
|
||||||
if (!SecurityUtils.getSubject().isAuthenticated()) {
|
if (!SecurityUtils.getSubject().isAuthenticated()) {
|
||||||
sendChallenge = true;
|
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
|
String authcHeader = HttpServletRequest.BASIC_AUTH + " realm=\"" + appName + "\"";
|
||||||
|
httpResponse.setHeader(AUTHENTICATE_HEADER, authcHeader);
|
||||||
|
existing = null;
|
||||||
}
|
}
|
||||||
|
} else if (ExceptionUtils.find(existing, IncorrectCredentialsException.class) != null) {
|
||||||
|
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Incorrect credentials.");
|
||||||
|
existing = null;
|
||||||
|
} else if (ExceptionUtils.find(existing, UnknownAccountException.class) != null) {
|
||||||
|
httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unknown user name.");
|
||||||
|
existing = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sendChallenge) {
|
|
||||||
existing = null;
|
|
||||||
sendChallenge(request, response);
|
|
||||||
}
|
|
||||||
|
|
||||||
super.cleanup(request, response, existing);
|
super.cleanup(request, response, existing);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected boolean sendChallenge(ServletRequest request, ServletResponse response) {
|
|
||||||
HttpServletResponse httpResponse = WebUtils.toHttp(response);
|
|
||||||
httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
|
||||||
String authcHeader = HttpServletRequest.BASIC_AUTH + " realm=\"" + appName + "\"";
|
|
||||||
httpResponse.setHeader(AUTHENTICATE_HEADER, authcHeader);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import java.util.Collection;
|
|||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
|
import org.apache.shiro.web.filter.mgt.FilterChainManager;
|
||||||
import org.hibernate.cfg.NamingStrategy;
|
import org.hibernate.cfg.NamingStrategy;
|
||||||
|
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
@ -14,6 +15,7 @@ import com.pmease.commons.jetty.ServletConfigurator;
|
|||||||
import com.pmease.commons.loader.AbstractPlugin;
|
import com.pmease.commons.loader.AbstractPlugin;
|
||||||
import com.pmease.commons.loader.AbstractPluginModule;
|
import com.pmease.commons.loader.AbstractPluginModule;
|
||||||
import com.pmease.commons.shiro.AbstractRealm;
|
import com.pmease.commons.shiro.AbstractRealm;
|
||||||
|
import com.pmease.commons.shiro.FilterChainConfigurator;
|
||||||
import com.pmease.commons.util.ClassUtils;
|
import com.pmease.commons.util.ClassUtils;
|
||||||
import com.pmease.gitop.core.model.ModelLocator;
|
import com.pmease.gitop.core.model.ModelLocator;
|
||||||
import com.pmease.gitop.core.permission.UserRealm;
|
import com.pmease.gitop.core.permission.UserRealm;
|
||||||
@ -69,6 +71,18 @@ public class CoreModule extends AbstractPluginModule {
|
|||||||
return Sets.newHashSet();
|
return Sets.newHashSet();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
contribute(FilterChainConfigurator.class, new FilterChainConfigurator() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configure(FilterChainManager filterChainManager) {
|
||||||
|
filterChainManager.createChain("/**/info/refs", "noSessionCreation, authcBasic");
|
||||||
|
filterChainManager.createChain("/**/git-upload-pack", "noSessionCreation, authcBasic");
|
||||||
|
filterChainManager.createChain("/**/git-receive-pack", "noSessionCreation, authcBasic");
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@ -48,6 +48,13 @@ public class CoreServletConfigurator implements ServletConfigurator {
|
|||||||
|
|
||||||
filterHolder = new FilterHolder(gitFilter);
|
filterHolder = new FilterHolder(gitFilter);
|
||||||
context.addFilter(filterHolder, "/*", EnumSet.allOf(DispatcherType.class));
|
context.addFilter(filterHolder, "/*", EnumSet.allOf(DispatcherType.class));
|
||||||
|
|
||||||
|
/*
|
||||||
|
ServletHolder servletHolder = new ServletHolder(new GitServlet());
|
||||||
|
servletHolder.setInitParameter("export-all", "1");
|
||||||
|
servletHolder.setInitParameter("base-path", "w:\\temp\\storage\\1");
|
||||||
|
context.addServlet(servletHolder, "/git/*");
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,12 +16,14 @@ import javax.servlet.http.HttpServletResponse;
|
|||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.shiro.SecurityUtils;
|
import org.apache.shiro.SecurityUtils;
|
||||||
import org.apache.shiro.authz.UnauthorizedException;
|
import org.apache.shiro.authz.UnauthorizedException;
|
||||||
|
import org.eclipse.jgit.http.server.GitSmartHttpTools;
|
||||||
import org.eclipse.jgit.http.server.ServletUtils;
|
import org.eclipse.jgit.http.server.ServletUtils;
|
||||||
import org.eclipse.jgit.transport.PacketLineOut;
|
import org.eclipse.jgit.transport.PacketLineOut;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
import com.pmease.commons.git.Git;
|
import com.pmease.commons.git.Git;
|
||||||
|
import com.pmease.commons.util.GeneralException;
|
||||||
import com.pmease.gitop.core.manager.ProjectManager;
|
import com.pmease.gitop.core.manager.ProjectManager;
|
||||||
import com.pmease.gitop.core.model.Project;
|
import com.pmease.gitop.core.model.Project;
|
||||||
import com.pmease.gitop.core.permission.ObjectPermission;
|
import com.pmease.gitop.core.permission.ObjectPermission;
|
||||||
@ -40,9 +42,13 @@ public class GitFilter implements Filter {
|
|||||||
this.projectManager = projectManager;
|
this.projectManager = projectManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Project getProject(HttpServletRequest request, HttpServletResponse response, String pathInfo, String repoInfo)
|
private String getPathInfo(HttpServletRequest request) {
|
||||||
|
String pathInfo = request.getRequestURI().substring(request.getContextPath().length());
|
||||||
|
return StringUtils.stripStart(pathInfo, "/");
|
||||||
|
}
|
||||||
|
|
||||||
|
private Project getProject(HttpServletRequest request, HttpServletResponse response, String repoInfo)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
|
|
||||||
repoInfo = StringUtils.stripStart(StringUtils.stripEnd(repoInfo, "/"), "/");
|
repoInfo = StringUtils.stripStart(StringUtils.stripEnd(repoInfo, "/"), "/");
|
||||||
|
|
||||||
String ownerName = StringUtils.substringBefore(repoInfo, "/");
|
String ownerName = StringUtils.substringBefore(repoInfo, "/");
|
||||||
@ -50,11 +56,8 @@ public class GitFilter implements Filter {
|
|||||||
|
|
||||||
if (StringUtils.isBlank(ownerName) || StringUtils.isBlank(projectName)) {
|
if (StringUtils.isBlank(ownerName) || StringUtils.isBlank(projectName)) {
|
||||||
String url = request.getRequestURL().toString();
|
String url = request.getRequestURL().toString();
|
||||||
String urlRoot = url.substring(0, url.length()-pathInfo.length());
|
String urlRoot = url.substring(0, url.length()-getPathInfo(request).length());
|
||||||
String message = "Expecting url of format " + urlRoot + "<owner name>/<project name>";
|
throw new GeneralException("Expecting url of format %s<owner name>/<project name>", urlRoot);
|
||||||
logger.error("Error serving git request: " + message);
|
|
||||||
response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (projectName.endsWith(".git"))
|
if (projectName.endsWith(".git"))
|
||||||
@ -62,10 +65,7 @@ public class GitFilter implements Filter {
|
|||||||
|
|
||||||
Project project = projectManager.find(ownerName, projectName);
|
Project project = projectManager.find(ownerName, projectName);
|
||||||
if (project == null) {
|
if (project == null) {
|
||||||
String message = "Unable to find project '" + projectName + "' owned by '" + ownerName + "'.";
|
throw new GeneralException("Unable to find project %s owned by %s.", projectName, ownerName);
|
||||||
logger.error("Error serving git request: " + message);
|
|
||||||
response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return project;
|
return project;
|
||||||
@ -77,77 +77,64 @@ public class GitFilter implements Filter {
|
|||||||
response.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate");
|
response.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate");
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void processPacks(HttpServletRequest req, HttpServletResponse resp, String pathInfo) throws ServletException, IOException {
|
protected void processPacks(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
|
String pathInfo = getPathInfo(request);
|
||||||
|
|
||||||
String service = StringUtils.substringAfterLast(pathInfo, "/");
|
String service = StringUtils.substringAfterLast(pathInfo, "/");
|
||||||
|
|
||||||
String repoInfo = StringUtils.substringBeforeLast(pathInfo, "/");
|
String repoInfo = StringUtils.substringBeforeLast(pathInfo, "/");
|
||||||
Project project = getProject(req, resp, pathInfo, repoInfo);
|
Project project = getProject(request, response, repoInfo);
|
||||||
|
|
||||||
if (project != null) {
|
doNotCache(response);
|
||||||
doNotCache(resp);
|
response.setHeader("Content-Type", "application/x-" + service + "-result");
|
||||||
resp.setHeader("Content-Type", "application/x-" + service + "-result");
|
|
||||||
|
|
||||||
Git git = new Git(projectManager.locateStorage(project).ofCode());
|
Git git = new Git(projectManager.locateStorage(project).ofCode());
|
||||||
|
|
||||||
if (service.contains("upload")) {
|
if (GitSmartHttpTools.isUploadPack(request)) {
|
||||||
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
|
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
|
||||||
throw new UnauthorizedException("You do not have permission to pull from this project.");
|
throw new UnauthorizedException("You do not have permission to pull from this project.");
|
||||||
}
|
|
||||||
git.upload().input(ServletUtils.getInputStream(req)).output(resp.getOutputStream()).call();
|
|
||||||
} else if (service.contains("receive")) {
|
|
||||||
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectWrite(project))) {
|
|
||||||
throw new UnauthorizedException("You do not have permission to push to this project.");
|
|
||||||
}
|
|
||||||
git.receive().input(ServletUtils.getInputStream(req)).output(resp.getOutputStream()).call();
|
|
||||||
} else {
|
|
||||||
String message = "Invalid service name '" + service + "'.";
|
|
||||||
logger.error("Error serving git request: " + message);
|
|
||||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
|
|
||||||
}
|
}
|
||||||
|
git.upload().input(ServletUtils.getInputStream(request)).output(response.getOutputStream()).call();
|
||||||
|
} else {
|
||||||
|
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectWrite(project))) {
|
||||||
|
throw new UnauthorizedException("You do not have permission to push to this project.");
|
||||||
|
}
|
||||||
|
git.receive().input(ServletUtils.getInputStream(request)).output(response.getOutputStream()).call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void writeInitial(HttpServletResponse resp, String service) throws IOException {
|
private void writeInitial(HttpServletResponse response, String service) throws IOException {
|
||||||
doNotCache(resp);
|
doNotCache(response);
|
||||||
resp.setHeader("Content-Type", "application/x-" + service + "-advertisement");
|
response.setHeader("Content-Type", "application/x-" + service + "-advertisement");
|
||||||
|
|
||||||
PacketLineOut pack = new PacketLineOut(resp.getOutputStream());
|
PacketLineOut pack = new PacketLineOut(response.getOutputStream());
|
||||||
pack.setFlushOnEnd(false);
|
pack.setFlushOnEnd(false);
|
||||||
pack.writeString("# service=" + service + "\n");
|
pack.writeString("# service=" + service + "\n");
|
||||||
pack.end();
|
pack.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void processRefs(HttpServletRequest req, HttpServletResponse resp, String pathInfo) throws ServletException, IOException {
|
protected void processRefs(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
|
||||||
if (!pathInfo.endsWith(INFO_REFS)) {
|
String pathInfo = request.getRequestURI().substring(request.getContextPath().length());
|
||||||
String message = "Invalid refs request url: " + req.getRequestURL();
|
pathInfo = StringUtils.stripStart(pathInfo, "/");
|
||||||
logger.error("Error serving git request: " + message);
|
|
||||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String repoInfo = pathInfo.substring(0, pathInfo.length() - INFO_REFS.length());
|
|
||||||
Project project = getProject(req, resp, pathInfo, repoInfo);
|
|
||||||
if (project != null) {
|
|
||||||
String service = req.getParameter("service");
|
|
||||||
Git git = new Git(projectManager.locateStorage(project).ofCode());
|
|
||||||
|
|
||||||
if (service.contains("upload")) {
|
String repoInfo = pathInfo.substring(0, pathInfo.length() - INFO_REFS.length());
|
||||||
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
|
Project project = getProject(request, response, repoInfo);
|
||||||
throw new UnauthorizedException("You do not have permission to pull from this project.");
|
String service = request.getParameter("service");
|
||||||
}
|
|
||||||
writeInitial(resp, service);
|
Git git = new Git(projectManager.locateStorage(project).ofCode());
|
||||||
git.advertiseUploadRefs().output(resp.getOutputStream()).call();
|
|
||||||
} else if (service.contains("receive")) {
|
if (service.contains("upload")) {
|
||||||
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectWrite(project))) {
|
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
|
||||||
throw new UnauthorizedException("You do not have permission to push to this project.");
|
throw new UnauthorizedException("You do not have permission to pull from this project.");
|
||||||
}
|
|
||||||
writeInitial(resp, service);
|
|
||||||
git.advertiseReceiveRefs().output(resp.getOutputStream()).call();
|
|
||||||
} else {
|
|
||||||
String message = "Invalid service name '" + service + "'.";
|
|
||||||
logger.error("Error serving git request: " + message);
|
|
||||||
resp.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
|
|
||||||
}
|
}
|
||||||
|
writeInitial(response, service);
|
||||||
|
git.advertiseUploadRefs().output(response.getOutputStream()).call();
|
||||||
|
} else {
|
||||||
|
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectWrite(project))) {
|
||||||
|
throw new UnauthorizedException("You do not have permission to push to this project.");
|
||||||
|
}
|
||||||
|
writeInitial(response, service);
|
||||||
|
git.advertiseReceiveRefs().output(response.getOutputStream()).call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,15 +147,17 @@ public class GitFilter implements Filter {
|
|||||||
FilterChain chain) throws IOException, ServletException {
|
FilterChain chain) throws IOException, ServletException {
|
||||||
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
HttpServletRequest httpRequest = (HttpServletRequest) request;
|
||||||
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
HttpServletResponse httpResponse = (HttpServletResponse) response;
|
||||||
String pathInfo = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
|
try {
|
||||||
pathInfo = StringUtils.stripStart(pathInfo, "/");
|
if (GitSmartHttpTools.isInfoRefs(httpRequest)) {
|
||||||
|
processRefs(httpRequest, httpResponse);
|
||||||
if (pathInfo.endsWith(INFO_REFS)) {
|
} else if (GitSmartHttpTools.isReceivePack(httpRequest) || GitSmartHttpTools.isUploadPack(httpRequest)) {
|
||||||
processRefs(httpRequest, httpResponse, pathInfo);
|
processPacks(httpRequest, httpResponse);
|
||||||
} else if (pathInfo.endsWith("git-receive-pack") || pathInfo.endsWith("git-upload-pack")) {
|
} else {
|
||||||
processPacks(httpRequest, httpResponse, pathInfo);
|
chain.doFilter(request, response);
|
||||||
} else {
|
}
|
||||||
chain.doFilter(request, response);
|
} catch (GeneralException e) {
|
||||||
|
logger.error("Error serving git request", e);
|
||||||
|
GitSmartHttpTools.sendError(httpRequest, httpResponse, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -60,7 +60,8 @@ public class AccountHomePage extends AbstractLayoutPage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void detachModels() {
|
public void detachModels() {
|
||||||
accountModel.detach();
|
if (accountModel != null)
|
||||||
|
accountModel.detach();
|
||||||
|
|
||||||
super.detachModels();
|
super.detachModels();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -54,7 +54,8 @@ public class ProjectHomePage extends AbstractLayoutPage {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void detachModels() {
|
public void detachModels() {
|
||||||
projectModel.detach();
|
if (projectModel != null)
|
||||||
|
projectModel.detach();
|
||||||
super.detachModels();
|
super.detachModels();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user