From 85f639aa3eee0b4e02eba20e6a5197b684941544 Mon Sep 17 00:00:00 2001
From: Luca Milanesio <luca.milanesio@gmail.com>
Date: Fri, 19 Oct 2012 21:53:24 -0400
Subject: [PATCH] Allows integration of GitBlit as plug-in in other projects.

---
 src/com/gitblit/GitBlit.java                       |   74 +++++++++++++++---
 src/com/gitblit/wicket/pages/RepositoriesPage.java |    4 
 .gitignore                                         |    1 
 src/com/gitblit/wicket/pages/BasePage.java         |   18 ++--
 tmplt.pom.xml                                      |    7 +
 build.xml                                          |   75 ++++++++++++++++++
 pom.xml                                            |    7 +
 src/com/gitblit/models/UserModel.java              |    7 +
 src/com/gitblit/wicket/pages/RepositoryPage.java   |   16 +++
 9 files changed, 181 insertions(+), 28 deletions(-)

diff --git a/.gitignore b/.gitignore
index e93e18e..173bd34 100644
--- a/.gitignore
+++ b/.gitignore
@@ -27,3 +27,4 @@
 *.directory
 /.gradle
 /projects.conf
+/pom.xml
diff --git a/build.xml b/build.xml
index 86b613b..6dca87d 100644
--- a/build.xml
+++ b/build.xml
@@ -14,9 +14,12 @@
 	<property name="project.build.dir" value="${basedir}/build" />
 	<property name="project.deploy.dir" value="${basedir}/deploy" />
 	<property name="project.war.dir" value="${basedir}/war" />
+	<property name="project.jar.dir" value="${basedir}/jar" />
 	<property name="project.site.dir" value="${basedir}/site" />
 	<property name="project.resources.dir" value="${basedir}/resources" />	
 	<property name="project.express.dir" value="${basedir}/express" />
+	<property name="project.maven.repo.url" value="enter here your Maven repo URL" />
+	<property name="project.maven.repo.id" value="gitblit.maven.repo" />
 	<available property="hasBuildProps" file="${basedir}/build.properties"/>
 
 	<!--
@@ -85,6 +88,8 @@
 		</loadfile>	
 		<property name="distribution.zipfile" value="gitblit-${gb.version}.zip" />
 		<property name="distribution.warfile" value="gitblit-${gb.version}.war" />
+		<property name="distribution.jarfile" value="gitblit-${gb.version}.jar" />
+		<property name="distribution.pomfile" value="${basedir}/pom.xml" />
 		<property name="fedclient.zipfile" value="fedclient-${gb.version}.zip" />
 		<property name="manager.zipfile" value="manager-${gb.version}.zip" />
 		<property name="gbapi.zipfile" value="gbapi-${gb.version}.zip" />
@@ -441,6 +446,76 @@
 	</target>
 
 	
+	<!--
+		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		Build Gitblit JAR for usage in other projects plug-ins (i.e. Gerrit)
+		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	-->
+	<target name="buildJAR" depends="compile" description="Build Gitblit JAR">
+
+		<echo>Building Gitblit JAR ${gb.version}</echo>
+
+		<delete dir="${project.jar.dir}" />
+
+		<!-- Gitblit classes -->
+		<mkdir dir="${project.jar.dir}"/>
+		<copy todir="${project.jar.dir}">
+			<fileset dir="${project.build.dir}">
+				<exclude name="WEB-INF/" />
+				<exclude name="com/gitblit/tests/" />
+				<exclude name="com/gitblit/build/**" />
+				<exclude name="com/gitblit/client/**" />
+				<exclude name="com/gitblit/AddIndexedBranch*.class" />
+				<exclude name="com/gitblit/GitBlitServer*.class" />
+				<exclude name="com/gitblit/Launcher*.class" />
+				<exclude name="com/gitblit/MakeCertificate*.class" />
+			</fileset>
+		</copy>
+
+		<!-- Build the JAR file -->
+		<jar basedir="${project.jar.dir}" destfile="${distribution.jarfile}" compress="true" />
+	</target>
+
+	<!--
+		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		Build pom.xml for GitBlit JAR Maven module
+		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	-->
+	<target name="buildMaven" depends="buildJAR" description="Build pom.xml for Gitblit JAR Maven module">
+		<copy tofile="${distribution.pomfile}" file="${distribution.pomfileTmplt}"/>
+		<replace file="${distribution.pomfile}" token="@gb.version@" value="${gb.version}" />
+	</target>
+
+	<!--
+		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+		Install Gitblit JAR for usage as Maven module
+		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+	-->
+	<target name="installMaven" depends="buildMaven" description="Install Gitblit JAR as Maven module">
+		<exec executable="mvn">
+			<arg value="install:install-file" />
+			<arg value="-Dfile=${distribution.jarfile}" />
+			<arg value="-DpomFile=${distribution.pomfile}" />
+			<arg value="-DcreateChecksum=true" />
+		</exec>
+	</target>
+
+	<!--
+    	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    	Upload Gitblit JAR to remote Maven repository
+    	~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+    -->
+	<target name="uploadMaven" depends="buildJAR" description="Upload Gitblit JAR to remote Maven repository">
+		<exec executable="mvn">
+			<arg value="deploy:deploy-file" />
+			<arg value="-Dfile=${distribution.jarfile}" />
+			<arg value="-DpomFile=${distribution.pomfile}" />
+			<arg value="-Durl=${project.maven.repo.url}" />
+			<arg value="-DrepositoryId=${project.maven.repo.id}" />
+			<arg value="-DcreateChecksum=true" />
+		</exec>
+	</target>
+
 	<!-- 
 		~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 		Build the stand-alone, command-line Gitblit Federation Client
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..406e2f6
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,7 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+		<modelVersion>4.0.0</modelVersion>
+		<groupId>com.gitblit</groupId>
+		<artifactId>gitblit</artifactId>
+		<version>1.1.0</version>
+</project>
diff --git a/src/com/gitblit/GitBlit.java b/src/com/gitblit/GitBlit.java
index 36f5f35..a121703 100644
--- a/src/com/gitblit/GitBlit.java
+++ b/src/com/gitblit/GitBlit.java
@@ -55,8 +55,11 @@
 import javax.servlet.ServletContextEvent;
 import javax.servlet.ServletContextListener;
 import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
 
 import org.apache.wicket.protocol.http.WebResponse;
+import org.apache.wicket.resource.ContextRelativeResource;
+import org.apache.wicket.util.resource.ResourceStreamNotFoundException;
 import org.eclipse.jgit.lib.Repository;
 import org.eclipse.jgit.lib.RepositoryCache;
 import org.eclipse.jgit.lib.RepositoryCache.FileKey;
@@ -98,6 +101,7 @@
 import com.gitblit.utils.MetricUtils;
 import com.gitblit.utils.ObjectCache;
 import com.gitblit.utils.StringUtils;
+import com.gitblit.wicket.WicketUtils;
 
 /**
  * GitBlit is the servlet context listener singleton that acts as the core for
@@ -163,6 +167,11 @@
 			// set the static singleton reference
 			gitblit = this;
 		}
+	}
+
+	public GitBlit(final IUserService userService) {
+		this.userService = userService;
+		gitblit = this;
 	}
 
 	/**
@@ -507,6 +516,28 @@
 			}
 		}
 		return null;
+	}
+
+	/**
+	 * Authenticate a user based on HTTP request paramters.
+	 * This method is inteded to be used as fallback when other
+	 * means of authentication are failing (username / password or cookies).
+	 * @param httpRequest
+	 * @return a user object or null
+	 */
+	public UserModel authenticate(HttpServletRequest httpRequest) {
+		return null;
+	}
+
+	/**
+	 * Open a file resource using the Servlet container.
+	 * @param file to open
+	 * @return InputStream of the opened file
+	 * @throws ResourceStreamNotFoundException
+	 */
+	public InputStream getResourceAsStream(String file) throws ResourceStreamNotFoundException {
+		ContextRelativeResource res = WicketUtils.getResource(file);
+		return res.getResourceStream().getInputStream();
 	}
 
 	/**
@@ -2427,10 +2458,11 @@
 	 * Parse the properties file and aggregate all the comments by the setting
 	 * key. A setting model tracks the current value, the default value, the
 	 * description of the setting and and directives about the setting.
+	 * @param referencePropertiesInputStream
 	 * 
 	 * @return Map<String, SettingModel>
 	 */
-	private ServerSettings loadSettingModels() {
+	private ServerSettings loadSettingModels(InputStream referencePropertiesInputStream) {
 		ServerSettings settingsModel = new ServerSettings();
 		settingsModel.supportsCredentialChanges = userService.supportsCredentialChanges();
 		settingsModel.supportsDisplayNameChanges = userService.supportsDisplayNameChanges();
@@ -2440,7 +2472,7 @@
 			// Read bundled Gitblit properties to extract setting descriptions.
 			// This copy is pristine and only used for populating the setting
 			// models map.
-			InputStream is = servletContext.getResourceAsStream("/WEB-INF/reference.properties");
+			InputStream is = referencePropertiesInputStream;
 			BufferedReader propertiesReader = new BufferedReader(new InputStreamReader(is));
 			StringBuilder description = new StringBuilder();
 			SettingModel setting = new SettingModel();
@@ -2518,21 +2550,23 @@
 		logTimezone(Constants.NAME, getTimezone());
 
 		serverStatus = new ServerStatus(isGO());
-		String realm = settings.getString(Keys.realm.userService, "users.properties");
-		IUserService loginService = null;
-		try {
-			// check to see if this "file" is a login service class
-			Class<?> realmClass = Class.forName(realm);
-			loginService = (IUserService) realmClass.newInstance();
-		} catch (Throwable t) {
-			loginService = new GitblitUserService();
+
+		if (this.userService == null) {
+			String realm = settings.getString(Keys.realm.userService, "users.properties");
+			IUserService loginService = null;
+			try {
+				// check to see if this "file" is a login service class
+				Class<?> realmClass = Class.forName(realm);
+				loginService = (IUserService) realmClass.newInstance();
+			} catch (Throwable t) {
+				loginService = new GitblitUserService();
+			}
+			setUserService(loginService);
 		}
-		setUserService(loginService);
 		
 		// load and cache the project metadata
 		projectConfigs = new FileBasedConfig(getFileOrFolder(Keys.web.projectsFile, "projects.conf"), FS.detect());
 		getProjectConfigs();
-		
 		mailExecutor = new MailExecutor(settings);
 		if (mailExecutor.isReady()) {
 			logger.info("Mail executor is scheduled to process the message queue every 2 minutes.");
@@ -2587,6 +2621,10 @@
 	 */
 	@Override
 	public void contextInitialized(ServletContextEvent contextEvent) {
+		contextInitialized(contextEvent, contextEvent.getServletContext().getResourceAsStream("/WEB-INF/reference.properties"));
+	}
+
+	public void contextInitialized(ServletContextEvent contextEvent, InputStream referencePropertiesInputStream) {
 		servletContext = contextEvent.getServletContext();
 		if (settings == null) {
 			// Gitblit WAR is running in a servlet container
@@ -2627,7 +2665,7 @@
 			}
 		}
 		
-		settingsModel = loadSettingModels();
+		settingsModel = loadSettingModels(referencePropertiesInputStream);
 		serverStatus.servletContainer = servletContext.getServerInfo();
 	}
 
@@ -2710,4 +2748,14 @@
 		addToCachedRepositoryList(cloneModel);
 		return cloneModel;
 	}
+
+	/**
+	 * Allow to understand if GitBlit supports and is configured to allow
+	 * cookie-based authentication.
+	 * 
+	 * @return status of Cookie authentication enablement.
+	 */
+	public boolean allowCookieAuthentication() {
+		return GitBlit.getBoolean(Keys.web.allowCookieAuthentication, true) && userService.supportsCookies();
+	}
 }
diff --git a/src/com/gitblit/models/UserModel.java b/src/com/gitblit/models/UserModel.java
index 8b3fe82..f14c1ae 100644
--- a/src/com/gitblit/models/UserModel.java
+++ b/src/com/gitblit/models/UserModel.java
@@ -217,7 +217,7 @@
 		return permission;
 	}
 	
-	private boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) {
+	protected boolean canAccess(RepositoryModel repository, AccessRestrictionType ifRestriction, AccessPermission requirePermission) {
 		if (repository.accessRestriction.atLeast(ifRestriction)) {
 			AccessPermission permission = getRepositoryPermission(repository);
 			return permission.atLeast(requirePermission);
@@ -433,4 +433,9 @@
 		}
 		return nameVerified && emailVerified;
 	}
+	
+	public boolean hasBranchPermission(String repositoryName, String branch) {
+		// Default UserModel doesn't implement branch-level security. Other Realms (i.e. Gerrit) may override this method.
+		return hasRepositoryPermission(repositoryName);
+	}
 }
diff --git a/src/com/gitblit/wicket/pages/BasePage.java b/src/com/gitblit/wicket/pages/BasePage.java
index cce323f..4d37611 100644
--- a/src/com/gitblit/wicket/pages/BasePage.java
+++ b/src/com/gitblit/wicket/pages/BasePage.java
@@ -76,14 +76,14 @@
 		super();
 		logger = LoggerFactory.getLogger(getClass());
 		customizeHeader();
-		loginByCookie();
+		login();
 	}
 
 	public BasePage(PageParameters params) {
 		super(params);
 		logger = LoggerFactory.getLogger(getClass());
 		customizeHeader();
-		loginByCookie();
+		login();
 	}
 	
 	private void customizeHeader() {
@@ -127,16 +127,14 @@
 		super.onAfterRender();
 	}	
 
-	private void loginByCookie() {
-		if (!GitBlit.getBoolean(Keys.web.allowCookieAuthentication, false)) {
-			return;
-		}
-		UserModel user = null;
-
-		// Grab cookie from Browser Session
+	private void login() {
 		Cookie[] cookies = ((WebRequest) getRequestCycle().getRequest()).getCookies();
-		if (cookies != null && cookies.length > 0) {
+		UserModel user = null;
+		if (GitBlit.self().allowCookieAuthentication() && cookies != null && cookies.length > 0) {
+			// Grab cookie from Browser Session
 			user = GitBlit.self().authenticate(cookies);
+		} else {
+			user = GitBlit.self().authenticate(((WebRequest) getRequestCycle().getRequest()).getHttpServletRequest());
 		}
 
 		// Login the user
diff --git a/src/com/gitblit/wicket/pages/RepositoriesPage.java b/src/com/gitblit/wicket/pages/RepositoriesPage.java
index 36f2c6d..97c6aa2 100644
--- a/src/com/gitblit/wicket/pages/RepositoriesPage.java
+++ b/src/com/gitblit/wicket/pages/RepositoriesPage.java
@@ -17,7 +17,6 @@
 
 import java.io.File;
 import java.io.FileInputStream;
-import java.io.FileNotFoundException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.text.MessageFormat;
@@ -154,8 +153,7 @@
 		}
 		String message;
 		try {			
-			ContextRelativeResource res = WicketUtils.getResource(file);
-			InputStream is = res.getResourceStream().getInputStream();
+		    InputStream is = GitBlit.self().getResourceAsStream(file);
 			InputStreamReader reader = new InputStreamReader(is, Constants.CHARACTER_ENCODING);
 			message = MarkdownUtils.transformMarkdown(reader);
 			reader.close();
diff --git a/src/com/gitblit/wicket/pages/RepositoryPage.java b/src/com/gitblit/wicket/pages/RepositoryPage.java
index b7cade6..fd2cbcc 100644
--- a/src/com/gitblit/wicket/pages/RepositoryPage.java
+++ b/src/com/gitblit/wicket/pages/RepositoryPage.java
@@ -48,6 +48,7 @@
 import com.gitblit.PagesServlet;
 import com.gitblit.SyndicationServlet;
 import com.gitblit.models.ProjectModel;
+import com.gitblit.models.RefModel;
 import com.gitblit.models.RepositoryModel;
 import com.gitblit.models.SubmoduleModel;
 import com.gitblit.models.UserModel;
@@ -91,6 +92,19 @@
 		}
 		objectId = WicketUtils.getObject(params);
 		
+		if (objectId != null) {
+			RefModel branch = null;
+			if ((branch = JGitUtils.getBranch(getRepository(), objectId)) != null) {
+				boolean canAccess = GitBlitWebSession
+						.get()
+						.getUser()
+						.hasBranchPermission(getRepositoryModel().name,
+								branch.reference.getName());
+				if (!canAccess) {
+					error("Access denied", true);
+				}
+			}
+		}
 		if (StringUtils.isEmpty(repositoryName)) {
 			error(MessageFormat.format(getString("gb.repositoryNotSpecifiedFor"), getPageName()), true);
 		}
@@ -576,4 +590,4 @@
 			getRequestCycle().setRequestTarget(new RedirectRequestTarget(absoluteUrl));
 		}
 	}
-}
\ No newline at end of file
+}
diff --git a/tmplt.pom.xml b/tmplt.pom.xml
new file mode 100644
index 0000000..4abe4be
--- /dev/null
+++ b/tmplt.pom.xml
@@ -0,0 +1,7 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+		<modelVersion>4.0.0</modelVersion>
+		<groupId>com.gitblit</groupId>
+		<artifactId>gitblit</artifactId>
+		<version>@gb.version@</version>
+</project>

--
Gitblit v1.9.1