Send git error messages to git client. Disable session creation for git

operation.
This commit is contained in:
robin shine 2013-10-02 16:13:56 +08:00
parent ff4dd0b7cf
commit 4e10bbc1b6
6 changed files with 104 additions and 91 deletions

View File

@ -12,6 +12,8 @@ import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.authz.UnauthenticatedException;
import org.apache.shiro.authz.UnauthorizedException;
@ -73,31 +75,30 @@ public class BasicAuthenticationFilter extends PathMatchingFilter {
protected void cleanup(ServletRequest request, ServletResponse response, Exception existing)
throws ServletException, IOException {
boolean sendChallenge = false;
HttpServletResponse httpResponse = WebUtils.toHttp(response);
if (existing != 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) {
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);
}
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;
}
}

View File

@ -4,6 +4,7 @@ import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import org.apache.shiro.web.filter.mgt.FilterChainManager;
import org.hibernate.cfg.NamingStrategy;
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.AbstractPluginModule;
import com.pmease.commons.shiro.AbstractRealm;
import com.pmease.commons.shiro.FilterChainConfigurator;
import com.pmease.commons.util.ClassUtils;
import com.pmease.gitop.core.model.ModelLocator;
import com.pmease.gitop.core.permission.UserRealm;
@ -69,6 +71,18 @@ public class CoreModule extends AbstractPluginModule {
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

View File

@ -48,6 +48,13 @@ public class CoreServletConfigurator implements ServletConfigurator {
filterHolder = new FilterHolder(gitFilter);
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/*");
*/
}
}

View File

@ -16,12 +16,14 @@ import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authz.UnauthorizedException;
import org.eclipse.jgit.http.server.GitSmartHttpTools;
import org.eclipse.jgit.http.server.ServletUtils;
import org.eclipse.jgit.transport.PacketLineOut;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.pmease.commons.git.Git;
import com.pmease.commons.util.GeneralException;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.model.Project;
import com.pmease.gitop.core.permission.ObjectPermission;
@ -40,9 +42,13 @@ public class GitFilter implements Filter {
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 {
repoInfo = StringUtils.stripStart(StringUtils.stripEnd(repoInfo, "/"), "/");
String ownerName = StringUtils.substringBefore(repoInfo, "/");
@ -50,11 +56,8 @@ public class GitFilter implements Filter {
if (StringUtils.isBlank(ownerName) || StringUtils.isBlank(projectName)) {
String url = request.getRequestURL().toString();
String urlRoot = url.substring(0, url.length()-pathInfo.length());
String message = "Expecting url of format " + urlRoot + "<owner name>/<project name>";
logger.error("Error serving git request: " + message);
response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
return null;
String urlRoot = url.substring(0, url.length()-getPathInfo(request).length());
throw new GeneralException("Expecting url of format %s<owner name>/<project name>", urlRoot);
}
if (projectName.endsWith(".git"))
@ -62,10 +65,7 @@ public class GitFilter implements Filter {
Project project = projectManager.find(ownerName, projectName);
if (project == null) {
String message = "Unable to find project '" + projectName + "' owned by '" + ownerName + "'.";
logger.error("Error serving git request: " + message);
response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
return null;
throw new GeneralException("Unable to find project %s owned by %s.", projectName, ownerName);
}
return project;
@ -77,77 +77,64 @@ public class GitFilter implements Filter {
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 repoInfo = StringUtils.substringBeforeLast(pathInfo, "/");
Project project = getProject(req, resp, pathInfo, repoInfo);
Project project = getProject(request, response, repoInfo);
if (project != null) {
doNotCache(resp);
resp.setHeader("Content-Type", "application/x-" + service + "-result");
doNotCache(response);
response.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 (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(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);
if (GitSmartHttpTools.isUploadPack(request)) {
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
throw new UnauthorizedException("You do not have permission to pull from this project.");
}
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 {
doNotCache(resp);
resp.setHeader("Content-Type", "application/x-" + service + "-advertisement");
private void writeInitial(HttpServletResponse response, String service) throws IOException {
doNotCache(response);
response.setHeader("Content-Type", "application/x-" + service + "-advertisement");
PacketLineOut pack = new PacketLineOut(resp.getOutputStream());
PacketLineOut pack = new PacketLineOut(response.getOutputStream());
pack.setFlushOnEnd(false);
pack.writeString("# service=" + service + "\n");
pack.end();
}
protected void processRefs(HttpServletRequest req, HttpServletResponse resp, String pathInfo) throws ServletException, IOException {
if (!pathInfo.endsWith(INFO_REFS)) {
String message = "Invalid refs request url: " + req.getRequestURL();
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());
protected void processRefs(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String pathInfo = request.getRequestURI().substring(request.getContextPath().length());
pathInfo = StringUtils.stripStart(pathInfo, "/");
if (service.contains("upload")) {
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
throw new UnauthorizedException("You do not have permission to pull from this project.");
}
writeInitial(resp, service);
git.advertiseUploadRefs().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.");
}
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);
String repoInfo = pathInfo.substring(0, pathInfo.length() - INFO_REFS.length());
Project project = getProject(request, response, repoInfo);
String service = request.getParameter("service");
Git git = new Git(projectManager.locateStorage(project).ofCode());
if (service.contains("upload")) {
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
throw new UnauthorizedException("You do not have permission to pull from this project.");
}
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 {
HttpServletRequest httpRequest = (HttpServletRequest) request;
HttpServletResponse httpResponse = (HttpServletResponse) response;
String pathInfo = httpRequest.getRequestURI().substring(httpRequest.getContextPath().length());
pathInfo = StringUtils.stripStart(pathInfo, "/");
if (pathInfo.endsWith(INFO_REFS)) {
processRefs(httpRequest, httpResponse, pathInfo);
} else if (pathInfo.endsWith("git-receive-pack") || pathInfo.endsWith("git-upload-pack")) {
processPacks(httpRequest, httpResponse, pathInfo);
} else {
chain.doFilter(request, response);
try {
if (GitSmartHttpTools.isInfoRefs(httpRequest)) {
processRefs(httpRequest, httpResponse);
} else if (GitSmartHttpTools.isReceivePack(httpRequest) || GitSmartHttpTools.isUploadPack(httpRequest)) {
processPacks(httpRequest, httpResponse);
} 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());
}
}

View File

@ -60,7 +60,8 @@ public class AccountHomePage extends AbstractLayoutPage {
@Override
public void detachModels() {
accountModel.detach();
if (accountModel != null)
accountModel.detach();
super.detachModels();
}

View File

@ -54,7 +54,8 @@ public class ProjectHomePage extends AbstractLayoutPage {
@Override
public void detachModels() {
projectModel.detach();
if (projectModel != null)
projectModel.detach();
super.detachModels();
}