diff --git a/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java b/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java index 07a5777270..d3b8786876 100644 --- a/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java +++ b/gitop.core/src/main/java/com/pmease/gitop/core/GitFilter.java @@ -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 + "//"; + String urlRoot = url.substring(0, url.length()-pathInfo.length()); + String message = "Expecting url of format " + urlRoot + "/"; 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, "/"); diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java index 1266a6643c..58bfeae399 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/TestPage.java @@ -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("form") { @@ -39,7 +36,7 @@ public class TestPage extends BasePage { add(form); } - + @Override protected String getPageTitle() { return "Test page used by Robin"; diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java b/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java index df8e520b32..01959743e3 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/WebUserNameReservation.java @@ -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) { diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/AbstractLayoutPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/AbstractLayoutPage.java index 8d7abea2c7..686ee789b0 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/AbstractLayoutPage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/AbstractLayoutPage.java @@ -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")); } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/BasePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/BasePage.java index 2ac07e43f0..85fcf926a7 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/BasePage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/BasePage.java @@ -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() { diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java index b3d5b5bcd0..c72ed731a0 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/AccountHomePage.java @@ -36,12 +36,7 @@ public class AccountHomePage extends AbstractLayoutPage { } }; - } - - @Override - protected void onInitialize() { - super.onInitialize(); - + add(new Label("accountName", getAccount().getName())); add(new Link("link") { @@ -53,7 +48,7 @@ public class AccountHomePage extends AbstractLayoutPage { }); } - + @Override protected String getPageTitle() { return "Gitop"; diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/RegisterPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/RegisterPage.java index 82f29b4eeb..0c505ec17f 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/RegisterPage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/RegisterPage.java @@ -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 model = Model.of(new User()); Form form = new Form("form", model); add(form); diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/AccountSettingPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/AccountSettingPage.java index 786f6ef2b4..ae944b6277 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/AccountSettingPage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/AccountSettingPage.java @@ -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("setting", ImmutableList.copyOf(Category.values())) { diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/password/AccountPasswordPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/password/AccountPasswordPage.java index 67c5995aa2..99d16b7a99 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/password/AccountPasswordPage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/password/AccountPasswordPage.java @@ -34,10 +34,7 @@ public class AccountPasswordPage extends AccountSettingPage { return Category.PASSWORD; } - @Override - protected void onInitialize() { - super.onInitialize(); - + public AccountPasswordPage() { Form form = new Form("form", new UserModel(getAccount())); add(form); form.add(new PasswordFieldElement("oldPass", "Current Password", diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/profile/AccountProfilePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/profile/AccountProfilePage.java index 646c2a8dde..efa559fd2c 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/profile/AccountProfilePage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/account/setting/profile/AccountProfilePage.java @@ -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 { public ProfileForm(String id, IModel model) { diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html index 71c2188950..6039c239f2 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.html @@ -6,6 +6,5 @@
account - project \ No newline at end of file diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java index 5efee2a736..68fbde9dc8 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/home/HomePage.java @@ -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)))); - } } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/init/ServerInitPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/init/ServerInitPage.java index 076ad2b29a..17ff590de2 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/init/ServerInitPage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/init/ServerInitPage.java @@ -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 configSteps = new ArrayList(); - 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 configSteps = new ArrayList(); + 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"; diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.html b/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.html index 3d08112ea0..99da38ed38 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.html +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.html @@ -3,7 +3,5 @@

Welcome, Project Home

- - link \ No newline at end of file diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.java b/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.java index 77295e700d..47a3d4cf3b 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/page/project/ProjectHomePage.java @@ -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("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(); } diff --git a/gitop.web/src/main/java/com/pmease/gitop/web/shiro/LoginPage.java b/gitop.web/src/main/java/com/pmease/gitop/web/shiro/LoginPage.java index d9ef3ac878..4c0cb007e5 100644 --- a/gitop.web/src/main/java/com/pmease/gitop/web/shiro/LoginPage.java +++ b/gitop.web/src/main/java/com/pmease/gitop/web/shiro/LoginPage.java @@ -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 { public LoginForm(String id) {