From 94b96b5a98bef254128ccc4f5fc0e0c4376324e4 Mon Sep 17 00:00:00 2001 From: James Moger Date: Wed, 13 Apr 2011 17:45:22 -0400 Subject: [PATCH] Start of webapp authentication. --- gitblit.properties | 3 + src/com/gitblit/Build.java | 2 +- .../{SecuredPage.java => AdminPage.java} | 2 +- .../gitblit/wicket/AuthorizationStrategy.java | 45 ++++++++ src/com/gitblit/wicket/BasePage.html | 2 +- src/com/gitblit/wicket/BasePage.java | 10 +- src/com/gitblit/wicket/GitBlitWebApp.java | 47 ++++++-- src/com/gitblit/wicket/GitBlitWebSession.java | 15 +++ src/com/gitblit/wicket/LoginPage.html | 37 +++++++ src/com/gitblit/wicket/LoginPage.java | 101 ++++++++++++++++++ src/com/gitblit/wicket/User.java | 23 ++++ 11 files changed, 275 insertions(+), 12 deletions(-) rename src/com/gitblit/wicket/{SecuredPage.java => AdminPage.java} (85%) create mode 100644 src/com/gitblit/wicket/AuthorizationStrategy.java create mode 100644 src/com/gitblit/wicket/LoginPage.html create mode 100644 src/com/gitblit/wicket/LoginPage.java create mode 100644 src/com/gitblit/wicket/User.java diff --git a/gitblit.properties b/gitblit.properties index b06adc26..a2e9ab66 100644 --- a/gitblit.properties +++ b/gitblit.properties @@ -26,6 +26,9 @@ cloneUrl = https://localhost/git/ # Require authentication for http/https push/pull access of git repositories authenticatePushPull = true +# Require authentication to see the web ui +authenticateWebUI = true + # Simple user realm file to authenticate users for push/pull realmFile = users.properties diff --git a/src/com/gitblit/Build.java b/src/com/gitblit/Build.java index 08202ba1..0af7390c 100644 --- a/src/com/gitblit/Build.java +++ b/src/com/gitblit/Build.java @@ -100,7 +100,7 @@ public class Build { * the byte array * @return the SHA1 checksum */ - private static String getSHA1(byte[] data) { + public static String getSHA1(byte[] data) { MessageDigest md; try { md = MessageDigest.getInstance("SHA-1"); diff --git a/src/com/gitblit/wicket/SecuredPage.java b/src/com/gitblit/wicket/AdminPage.java similarity index 85% rename from src/com/gitblit/wicket/SecuredPage.java rename to src/com/gitblit/wicket/AdminPage.java index c3153a67..2f8345b4 100644 --- a/src/com/gitblit/wicket/SecuredPage.java +++ b/src/com/gitblit/wicket/AdminPage.java @@ -7,5 +7,5 @@ import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) -public @interface SecuredPage { +public @interface AdminPage { } diff --git a/src/com/gitblit/wicket/AuthorizationStrategy.java b/src/com/gitblit/wicket/AuthorizationStrategy.java new file mode 100644 index 00000000..b99ad6de --- /dev/null +++ b/src/com/gitblit/wicket/AuthorizationStrategy.java @@ -0,0 +1,45 @@ +package com.gitblit.wicket; + +import org.apache.wicket.Component; +import org.apache.wicket.RestartResponseAtInterceptPageException; +import org.apache.wicket.authorization.IUnauthorizedComponentInstantiationListener; +import org.apache.wicket.authorization.strategies.page.AbstractPageAuthorizationStrategy; + +import com.gitblit.wicket.pages.RepositoriesPage; + +public class AuthorizationStrategy extends AbstractPageAuthorizationStrategy implements IUnauthorizedComponentInstantiationListener { + + public AuthorizationStrategy() { + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + protected boolean isPageAuthorized(Class pageClass) { + if (BasePage.class.isAssignableFrom(pageClass)) + return isAuthorized(pageClass); + // Return contruction by default + return true; + } + + @Override + public void onUnauthorizedInstantiation(Component component) { + if (component instanceof BasePage) { + GitBlitWebSession session = GitBlitWebSession.get(); + if (!session.isLoggedIn()) + throw new RestartResponseAtInterceptPageException(LoginPage.class); + else + throw new RestartResponseAtInterceptPageException(RepositoriesPage.class); + } + } + + protected boolean isAuthorized(Class pageClass) { + GitBlitWebSession session = GitBlitWebSession.get(); + if (!session.isLoggedIn()) + return false; + User user = session.getUser(); + if (pageClass.isAnnotationPresent(AdminPage.class)) { + + } + return true; + } +} diff --git a/src/com/gitblit/wicket/BasePage.html b/src/com/gitblit/wicket/BasePage.html index dabdb560..9ca9f13e 100644 --- a/src/com/gitblit/wicket/BasePage.html +++ b/src/com/gitblit/wicket/BasePage.html @@ -32,7 +32,7 @@
-
[footer text]
+
[user text]
\ No newline at end of file diff --git a/src/com/gitblit/wicket/BasePage.java b/src/com/gitblit/wicket/BasePage.java index 3121804a..8084b335 100644 --- a/src/com/gitblit/wicket/BasePage.java +++ b/src/com/gitblit/wicket/BasePage.java @@ -26,7 +26,7 @@ public abstract class BasePage extends WebPage { public BasePage(PageParameters params) { super(params); } - + protected void setupPage(String repositoryName, String pageName) { if (repositoryName != null && repositoryName.trim().length() > 0) { add(new Label("title", getServerName() + " - " + repositoryName)); @@ -43,7 +43,13 @@ public abstract class BasePage extends WebPage { add(new Label("pageName", pageName)); // footer - add(new Label("footerText", "")); + User user = null; + if (StoredSettings.getBoolean("authenticateWebUI", true)) { + user = GitBlitWebSession.get().getUser(); + add(new Label("userText", "Logout " + user.toString())); + } else { + add(new Label("userText", "")); + } add(new Label("gbVersion", "v" + Constants.VERSION)); if (StoredSettings.getBoolean("aggressiveHeapManagement", false)) { System.gc(); diff --git a/src/com/gitblit/wicket/GitBlitWebApp.java b/src/com/gitblit/wicket/GitBlitWebApp.java index a1de7d65..2bd3179d 100644 --- a/src/com/gitblit/wicket/GitBlitWebApp.java +++ b/src/com/gitblit/wicket/GitBlitWebApp.java @@ -5,6 +5,7 @@ import java.util.ArrayList; import java.util.Date; import java.util.List; +import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import org.apache.wicket.Application; @@ -13,6 +14,7 @@ import org.apache.wicket.Request; import org.apache.wicket.Response; import org.apache.wicket.Session; import org.apache.wicket.protocol.http.WebApplication; +import org.apache.wicket.protocol.http.WebResponse; import org.apache.wicket.protocol.http.request.urlcompressing.UrlCompressingWebRequestProcessor; import org.apache.wicket.protocol.http.servlet.ServletWebRequest; import org.apache.wicket.request.IRequestCycleProcessor; @@ -24,6 +26,7 @@ import org.eclipse.jgit.lib.Repository; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.gitblit.Constants; import com.gitblit.GitBlitServer; import com.gitblit.StoredSettings; import com.gitblit.utils.JGitUtils; @@ -31,8 +34,8 @@ import com.gitblit.wicket.models.RepositoryModel; import com.gitblit.wicket.pages.BlobDiffPage; import com.gitblit.wicket.pages.BlobPage; import com.gitblit.wicket.pages.BranchesPage; -import com.gitblit.wicket.pages.CommitPage; import com.gitblit.wicket.pages.CommitDiffPage; +import com.gitblit.wicket.pages.CommitPage; import com.gitblit.wicket.pages.LogPage; import com.gitblit.wicket.pages.PatchPage; import com.gitblit.wicket.pages.RawPage; @@ -44,11 +47,8 @@ import com.gitblit.wicket.pages.TicGitPage; import com.gitblit.wicket.pages.TicGitTicketPage; import com.gitblit.wicket.pages.TreePage; - public class GitBlitWebApp extends WebApplication { - public static int PAGING_ITEM_COUNT = 50; - Logger logger = LoggerFactory.getLogger(GitBlitWebApp.class); FileResolver repositoryResolver; @@ -61,8 +61,17 @@ public class GitBlitWebApp extends WebApplication { public void init() { super.init(); + // Setup page authorization mechanism + if (StoredSettings.getBoolean("authenticateWebUI", false)) { + AuthorizationStrategy authStrategy = new AuthorizationStrategy(); + getSecuritySettings().setAuthorizationStrategy(authStrategy); + getSecuritySettings().setUnauthorizedComponentInstantiationListener(authStrategy); + } + // Grab Browser info (like timezone, etc) - getRequestCycleSettings().setGatherExtendedBrowserInfo(true); + if (StoredSettings.getBoolean("useClientTimezone", false)) { + getRequestCycleSettings().setGatherExtendedBrowserInfo(true); + } // setup the standard gitweb-ish urls mount(new MixedParamUrlCodingStrategy("/summary", SummaryPage.class, new String[] { "r" })); @@ -77,11 +86,13 @@ public class GitBlitWebApp extends WebApplication { mount(new MixedParamUrlCodingStrategy("/blobdiff", BlobDiffPage.class, new String[] { "r", "h", "f" })); mount(new MixedParamUrlCodingStrategy("/commitdiff", CommitDiffPage.class, new String[] { "r", "h" })); mount(new MixedParamUrlCodingStrategy("/patch", PatchPage.class, new String[] { "r", "h", "f" })); - + // setup extended urls mount(new MixedParamUrlCodingStrategy("/ticgit", TicGitPage.class, new String[] { "r" })); mount(new MixedParamUrlCodingStrategy("/ticgittkt", TicGitTicketPage.class, new String[] { "r", "h", "f" })); - + + mount(new MixedParamUrlCodingStrategy("/login", LoginPage.class, new String[] {})); + repositories = new File(StoredSettings.getString("repositoriesFolder", "repos")); exportAll = StoredSettings.getBoolean("exportAll", true); repositoryResolver = new FileResolver(repositories, exportAll); @@ -109,6 +120,28 @@ public class GitBlitWebApp extends WebApplication { return Application.DEPLOYMENT; } + public User authenticate(String username, char [] password) { + return new User(username, password); + } + + public User authenticate(Cookie[] cookies) { + if (cookies != null && cookies.length > 0) { + for (Cookie cookie:cookies) { + if (cookie.getName().equals(Constants.NAME)) { + String value = cookie.getValue(); + } + } + } + return null; + } + + public void setCookie(WebResponse response, User user) { + Cookie userCookie = new Cookie(Constants.NAME, user.getCookie()); + userCookie.setMaxAge(Integer.MAX_VALUE); + userCookie.setPath("/"); + response.addCookie(userCookie); + } + public List getRepositoryList() { return JGitUtils.getRepositoryList(repositories, exportAll, StoredSettings.getBoolean("nestedRepositories", true)); } diff --git a/src/com/gitblit/wicket/GitBlitWebSession.java b/src/com/gitblit/wicket/GitBlitWebSession.java index 038118e5..b2106e7b 100644 --- a/src/com/gitblit/wicket/GitBlitWebSession.java +++ b/src/com/gitblit/wicket/GitBlitWebSession.java @@ -12,6 +12,8 @@ public final class GitBlitWebSession extends WebSession { private static final long serialVersionUID = 1L; protected TimeZone timezone = null; + + private User user = null; public GitBlitWebSession(Request request) { super(request); @@ -19,6 +21,19 @@ public final class GitBlitWebSession extends WebSession { public void invalidate() { super.invalidate(); + user = null; + } + + public boolean isLoggedIn() { + return user != null; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; } public TimeZone getTimezone() { diff --git a/src/com/gitblit/wicket/LoginPage.html b/src/com/gitblit/wicket/LoginPage.html new file mode 100644 index 00000000..adbe64f5 --- /dev/null +++ b/src/com/gitblit/wicket/LoginPage.html @@ -0,0 +1,37 @@ + + + + + + [page title] + + + + + + + + +
+
+
+ [name]
+ +
+
+

+ Username +

+ Password +

+ +

+
+
+
+
+ + \ No newline at end of file diff --git a/src/com/gitblit/wicket/LoginPage.java b/src/com/gitblit/wicket/LoginPage.java new file mode 100644 index 00000000..39b42852 --- /dev/null +++ b/src/com/gitblit/wicket/LoginPage.java @@ -0,0 +1,101 @@ +package com.gitblit.wicket; + +import javax.servlet.http.Cookie; +import javax.servlet.http.HttpServletRequest; + +import org.apache.wicket.PageParameters; +import org.apache.wicket.markup.html.WebPage; +import org.apache.wicket.markup.html.basic.Label; +import org.apache.wicket.markup.html.form.Form; +import org.apache.wicket.markup.html.form.PasswordTextField; +import org.apache.wicket.markup.html.form.TextField; +import org.apache.wicket.markup.html.image.ContextImage; +import org.apache.wicket.markup.html.panel.FeedbackPanel; +import org.apache.wicket.model.IModel; +import org.apache.wicket.model.Model; +import org.apache.wicket.protocol.http.WebRequest; +import org.apache.wicket.protocol.http.WebResponse; +import org.apache.wicket.protocol.http.servlet.ServletWebRequest; + +import com.gitblit.Constants; + +public class LoginPage extends WebPage { + + IModel username = new Model(""); + IModel password = new Model(""); + + public LoginPage(PageParameters params) { + super(params); + + tryAutomaticLogin(); + + add(new Label("title", getServerName())); + add(new ContextImage("logo", "gitblt2.png")); + add(new Label("name", Constants.NAME)); + + Form loginForm = new LoginForm("loginForm"); + loginForm.add(new TextField("username", username)); + loginForm.add(new PasswordTextField("password", password)); + loginForm.add(new FeedbackPanel("feedback")); + add(loginForm); + } + + protected String getServerName() { + ServletWebRequest servletWebRequest = (ServletWebRequest) getRequest(); + HttpServletRequest req = servletWebRequest.getHttpServletRequest(); + return req.getServerName(); + } + + class LoginForm extends Form { + private static final long serialVersionUID = 1L; + + public LoginForm(String id) { + super(id); + } + + @Override + public void onSubmit() { + String username = LoginPage.this.username.getObject(); + char [] password = LoginPage.this.password.getObject().toCharArray(); + + User user = GitBlitWebApp.get().authenticate(username, password); + if (user == null) + error("Invalid username or password!"); + else + loginUser(user); + } + } + + private void tryAutomaticLogin() { + User user = null; + + // Grab cookie from Browser Session + Cookie[] cookies = ((WebRequest) getRequestCycle().getRequest()).getCookies(); + if (cookies != null && cookies.length > 0) { + user = GitBlitWebApp.get().authenticate(cookies); + } + + // Login the user + loginUser(user); + } + + private void loginUser(User user) { + if (user != null) { + GitBlitWebSession session = GitBlitWebSession.get(); + + // Set Cookie + WebResponse response = (WebResponse) getRequestCycle().getResponse(); + GitBlitWebApp.get().setCookie(response, user); + + // track user object so that we do not have to continue + // re-authenticating on each request. + session.setUser(user); + + // Redirect to original page OR to first available tab + if (!continueToOriginalDestination()) { + // Redirect to home page + setResponsePage(session.getApplication().getHomePage()); + } + } + } +} diff --git a/src/com/gitblit/wicket/User.java b/src/com/gitblit/wicket/User.java new file mode 100644 index 00000000..fb49b404 --- /dev/null +++ b/src/com/gitblit/wicket/User.java @@ -0,0 +1,23 @@ +package com.gitblit.wicket; + +import com.gitblit.Build; +import com.gitblit.Constants; + +public class User { + + private String username; + private char [] password; + + public User(String username, char [] password) { + this.username = username; + this.password = password; + } + + public String getCookie() { + return Build.getSHA1((Constants.NAME + username + new String(password)).getBytes()); + } + + public String toString() { + return username; + } +} -- 2.39.5