Make BasePage.onInitialize() final.

Add security check for GitFilter
This commit is contained in:
robin shine 2013-10-01 22:54:27 +08:00
parent 0aab6f6089
commit ff4dd0b7cf
16 changed files with 144 additions and 150 deletions

View File

@ -14,6 +14,8 @@ import javax.servlet.http.HttpServletRequest;
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.ServletUtils;
import org.eclipse.jgit.transport.PacketLineOut;
import org.slf4j.Logger;
@ -22,6 +24,7 @@ import org.slf4j.LoggerFactory;
import com.pmease.commons.git.Git;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.model.Project;
import com.pmease.gitop.core.permission.ObjectPermission;
@Singleton
public class GitFilter implements Filter {
@ -37,7 +40,7 @@ public class GitFilter implements Filter {
this.projectManager = projectManager;
}
private Project getProject(HttpServletRequest request, HttpServletResponse response, String repoInfo)
private Project getProject(HttpServletRequest request, HttpServletResponse response, String pathInfo, String repoInfo)
throws IOException {
repoInfo = StringUtils.stripStart(StringUtils.stripEnd(repoInfo, "/"), "/");
@ -47,8 +50,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()-request.getPathInfo().length());
String message = "Expecting url of format " + urlRoot + "/<owner name>/<project name>";
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;
@ -61,7 +64,7 @@ public class GitFilter implements Filter {
if (project == null) {
String message = "Unable to find project '" + projectName + "' owned by '" + ownerName + "'.";
logger.error("Error serving git request: " + message);
response.sendError(HttpServletResponse.SC_BAD_REQUEST, message);
response.sendError(HttpServletResponse.SC_NOT_FOUND, message);
return null;
}
@ -78,7 +81,7 @@ public class GitFilter implements Filter {
String service = StringUtils.substringAfterLast(pathInfo, "/");
String repoInfo = StringUtils.substringBeforeLast(pathInfo, "/");
Project project = getProject(req, resp, repoInfo);
Project project = getProject(req, resp, pathInfo, repoInfo);
if (project != null) {
doNotCache(resp);
@ -86,23 +89,34 @@ public class GitFilter implements Filter {
Git git = new Git(projectManager.locateStorage(project).ofCode());
try {
if (service.contains("upload")) {
git.upload().input(ServletUtils.getInputStream(req)).output(resp.getOutputStream()).call();
} else if (service.contains("receive")) {
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 (service.contains("upload")) {
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
throw new UnauthorizedException("You do not have permission to pull from this project.");
}
} catch (Exception e) {
logger.error("Error serving git request.", e);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
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);
}
}
}
private void writeInitial(HttpServletResponse resp, String service) throws IOException {
doNotCache(resp);
resp.setHeader("Content-Type", "application/x-" + service + "-advertisement");
PacketLineOut pack = new PacketLineOut(resp.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();
@ -112,32 +126,27 @@ public class GitFilter implements Filter {
}
String repoInfo = pathInfo.substring(0, pathInfo.length() - INFO_REFS.length());
Project project = getProject(req, resp, repoInfo);
Project project = getProject(req, resp, pathInfo, repoInfo);
if (project != null) {
doNotCache(resp);
String service = req.getParameter("service");
resp.setHeader("Content-Type", "application/x-" + service + "-advertisement");
PacketLineOut pack = new PacketLineOut(resp.getOutputStream());
pack.setFlushOnEnd(false);
pack.writeString("# service=" + service + "\n");
pack.end();
Git git = new Git(projectManager.locateStorage(project).ofCode());
try {
if (service.contains("upload")) {
git.advertiseUploadRefs().output(resp.getOutputStream()).call();
} else if (service.contains("receive")) {
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);
if (service.contains("upload")) {
if (!SecurityUtils.getSubject().isPermitted(ObjectPermission.ofProjectRead(project))) {
throw new UnauthorizedException("You do not have permission to pull from this project.");
}
} catch (Exception e) {
logger.error("Error serving git request.", e);
resp.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, e.getMessage());
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);
}
}
}
@ -151,7 +160,6 @@ 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, "/");

View File

@ -14,10 +14,7 @@ import com.pmease.gitop.web.page.BasePage;
@SuppressWarnings("serial")
public class TestPage extends BasePage {
@Override
protected void onInitialize() {
super.onInitialize();
public TestPage() {
final EditContext editContext = EditableUtils.getContext(new Project());
Form<?> form = new Form<Void>("form") {
@ -39,7 +36,7 @@ public class TestPage extends BasePage {
add(form);
}
@Override
protected String getPageTitle() {
return "Test page used by Robin";

View File

@ -42,6 +42,7 @@ public class WebUserNameReservation implements UserNameReservation {
}
reserved.add("wicket");
reserved.add("rest");
for (IRequestMapper mapper: webApp.getRequestMappers()) {
if (mapper instanceof MountedMapper || mapper instanceof ResourceMapper) {

View File

@ -1,6 +1,8 @@
package com.pmease.gitop.web.page;
import org.apache.shiro.SecurityUtils;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import com.google.common.base.Optional;
import com.pmease.gitop.core.model.User;
@ -8,9 +10,21 @@ import com.pmease.gitop.core.model.User;
@SuppressWarnings("serial")
public abstract class AbstractLayoutPage extends BasePage {
@Override
protected void onInitialize() {
super.onInitialize();
public AbstractLayoutPage() {
commonInit();
}
public AbstractLayoutPage(PageParameters params) {
super(params);
commonInit();
}
public AbstractLayoutPage(IModel<?> model) {
super(model);
commonInit();
}
private void commonInit() {
add(new GlobalHeaderPanel("header"));
}

View File

@ -48,24 +48,10 @@ public abstract class BasePage extends WebPage {
return Strings.isNullOrEmpty(css) ? "" : css;
}
}));
if (!Gitop.getInstance().isReady() && getClass() != ServerInitPage.class) {
if (!isServerReady() && getClass() != ServerInitPage.class) {
throw new RestartResponseAtInterceptPageException(ServerInitPage.class);
}
}
protected String getPageCssClass() {
String name = getClass().getSimpleName();
return StringUtils.camelCaseToLowerCaseWithHyphen(name);
}
protected boolean isPermitted() {
return true;
}
@Override
protected void onInitialize() {
super.onInitialize();
if (!isPermitted()) {
throw new AccessDeniedException();
@ -100,6 +86,31 @@ public abstract class BasePage extends WebPage {
add(new WebMarkupContainer("globalResourceBinder").add(new BaseResourceBehavior()));
}
protected String getPageCssClass() {
String name = getClass().getSimpleName();
return StringUtils.camelCaseToLowerCaseWithHyphen(name);
}
protected boolean isPermitted() {
return true;
}
protected boolean isServerReady() {
return Gitop.getInstance().isReady();
}
/*
* For pages, we make this final to prevent sub classes from putting page initialization
* logics here. Instead, one should put all page initialization logic in page
* constructor to avoid the situation that if page constructor throws an exception
* intentionally (such as RestartResponseException) to by pass initialization logic
* but onInitialize will still be called to cause undesired behavior.
*/
@Override
protected final void onInitialize() {
super.onInitialize();
}
protected abstract String getPageTitle();
protected int getPageRefreshInterval() {

View File

@ -36,12 +36,7 @@ public class AccountHomePage extends AbstractLayoutPage {
}
};
}
@Override
protected void onInitialize() {
super.onInitialize();
add(new Label("accountName", getAccount().getName()));
add(new Link<Void>("link") {
@ -53,7 +48,7 @@ public class AccountHomePage extends AbstractLayoutPage {
});
}
@Override
protected String getPageTitle() {
return "Gitop";

View File

@ -40,11 +40,8 @@ public class RegisterPage extends AbstractLayoutPage {
protected String getPageTitle() {
return "Gitop - Sign Up";
}
@Override
protected void onInitialize() {
super.onInitialize();
public RegisterPage() {
final IModel<User> model = Model.<User>of(new User());
Form<User> form = new Form<User>("form", model);
add(form);

View File

@ -10,6 +10,8 @@ import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.model.AbstractReadOnlyModel;
import org.apache.wicket.model.IModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
import com.google.common.collect.ImmutableList;
import com.pmease.gitop.core.model.User;
@ -48,10 +50,21 @@ public abstract class AccountSettingPage extends AbstractLayoutPage {
}
}
@Override
protected void onInitialize() {
super.onInitialize();
public AccountSettingPage() {
commonInit();
}
public AccountSettingPage(PageParameters params) {
super(params);
commonInit();
}
public AccountSettingPage(IModel<?> model) {
super(model);
commonInit();
}
private void commonInit() {
add(new UserAvatarLink("userlink", new UserModel(getAccount())));
add(new ListView<Category>("setting", ImmutableList.<Category>copyOf(Category.values())) {

View File

@ -34,10 +34,7 @@ public class AccountPasswordPage extends AccountSettingPage {
return Category.PASSWORD;
}
@Override
protected void onInitialize() {
super.onInitialize();
public AccountPasswordPage() {
Form<User> form = new Form<User>("form", new UserModel(getAccount()));
add(form);
form.add(new PasswordFieldElement("oldPass", "Current Password",

View File

@ -27,14 +27,11 @@ public class AccountProfilePage extends AccountSettingPage {
protected Category getSettingCategory() {
return Category.PROFILE;
}
@Override
protected void onInitialize() {
super.onInitialize();
public AccountProfilePage() {
add(new ProfileForm("form", new UserModel(getAccount())));
}
private class ProfileForm extends Form<User> {
public ProfileForm(String id, IModel<User> model) {

View File

@ -6,6 +6,5 @@
<div wicket:id="upload"></div>
</div>
<a wicket:id="accountLink">account</a>
<a wicket:id="projectLink">project</a>
</wicket:extend>
</html>

View File

@ -3,29 +3,24 @@ package com.pmease.gitop.web.page.home;
import org.apache.wicket.markup.html.link.BookmarkablePageLink;
import com.pmease.gitop.core.Gitop;
import com.pmease.gitop.core.manager.ProjectManager;
import com.pmease.gitop.core.manager.UserManager;
import com.pmease.gitop.web.common.component.fileupload.FileUploadBar;
import com.pmease.gitop.web.page.AbstractLayoutPage;
import com.pmease.gitop.web.page.account.AccountHomePage;
import com.pmease.gitop.web.page.project.ProjectHomePage;
public class HomePage extends AbstractLayoutPage {
private static final long serialVersionUID = 1L;
public HomePage() {
add(new FileUploadBar("upload"));
add(new BookmarkablePageLink<>("accountLink", AccountHomePage.class, AccountHomePage.paramsOf(Gitop.getInstance(UserManager.class).getRootUser())));
}
@Override
protected String getPageTitle() {
return "Gitop - Home";
}
@Override
protected void onInitialize() {
super.onInitialize();
add(new FileUploadBar("upload"));
add(new BookmarkablePageLink<>("accountLink", AccountHomePage.class, AccountHomePage.paramsOf(Gitop.getInstance(UserManager.class).getRootUser())));
add(new BookmarkablePageLink<>("projectLink", ProjectHomePage.class, ProjectHomePage.paramsOf(Gitop.getInstance(ProjectManager.class).load(1L))));
}
}

View File

@ -25,33 +25,26 @@ public class ServerInitPage extends BasePage {
continueToOriginalDestination();
throw new RestartResponseException(getApplication().getHomePage());
}
}
@Override
protected void onInitialize() {
super.onInitialize();
if (initStage != null) {
add(new Label("message", initStage.getMessage()));
if (!initStage.getManualConfigs().isEmpty()) {
List<ManualConfigStep> configSteps = new ArrayList<ManualConfigStep>();
for (ManualConfig each: initStage.getManualConfigs())
configSteps.add(new ManualConfigStep(each));
add(new Wizard("wizard", configSteps) {
@Override
protected void finished() {
setResponsePage(ServerInitPage.class);
}
});
} else {
add(new WebMarkupContainer("wizard").setVisible(false));
}
add(new Label("message", initStage.getMessage()));
if (!initStage.getManualConfigs().isEmpty()) {
List<ManualConfigStep> configSteps = new ArrayList<ManualConfigStep>();
for (ManualConfig each: initStage.getManualConfigs())
configSteps.add(new ManualConfigStep(each));
add(new Wizard("wizard", configSteps) {
@Override
protected void finished() {
setResponsePage(ServerInitPage.class);
}
});
} else {
add(new WebMarkupContainer("wizard").setVisible(false));
}
}
@Override
protected String getPageTitle() {
return "Server Initialization";

View File

@ -3,7 +3,5 @@
<h1>Welcome, Project Home</h1>
<div wicket:id="accountName"></div>
<div wicket:id="projectName"></div>
<a wicket:id="link">link</a>
</wicket:extend>
</html>

View File

@ -1,7 +1,6 @@
package com.pmease.gitop.web.page.project;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.model.IModel;
import org.apache.wicket.model.LoadableDetachableModel;
import org.apache.wicket.request.mapper.parameter.PageParameters;
@ -45,24 +44,10 @@ public class ProjectHomePage extends AbstractLayoutPage {
};
add(new Link<Void>("link") {
@Override
public void onClick() {
}
});
}
@Override
protected void onInitialize() {
super.onInitialize();
add(new Label("accountName", getProject().getOwner().getName()));
add(new Label("projectName", getProject().getName()));
}
public Project getProject() {
return projectModel.getObject();
}

View File

@ -26,17 +26,11 @@ public class LoginPage extends AbstractLayoutPage {
if (isSignedIn()) {
throw new RestartResponseException(getApplication().getHomePage());
}
}
@Override
protected void onInitialize() {
super.onInitialize();
add(new LoginForm("login"));
FeedbackPanel feedback = new FeedbackPanel("feedback");
add(feedback);
}
private class LoginForm extends StatelessForm<Void> {
public LoginForm(String id) {