Luca Milanesio
2012-08-14 85f639aa3eee0b4e02eba20e6a5197b684941544
Allows integration of GitBlit as plug-in in other projects.

There are now three new targets on the ANT build:
- buildJAR: creates a GitBlit JAR including the GitBlit biz logic
- installMaven: install GitBlit JAR as Maven module
- uploadMaven: uploads GitBlit JAR to a Maven repository

Additional extensions have been made to allow:
a) GitBlit to load his resources outside of Wicket domain
b) GitBlit to use an injected UserService
c) Generic authentication of HTTP Request using 3rd party logic
d) Load settings programmatically from an InputStream
e) Use cookie authentication OR generic HTTP Request
authentication for Wicket pages
f) UserModel with branch-level security logic
2 files added
7 files modified
209 ■■■■ changed files
.gitignore 1 ●●●● patch | view | raw | blame | history
build.xml 75 ●●●●● patch | view | raw | blame | history
pom.xml 7 ●●●●● patch | view | raw | blame | history
src/com/gitblit/GitBlit.java 74 ●●●● patch | view | raw | blame | history
src/com/gitblit/models/UserModel.java 7 ●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/BasePage.java 18 ●●●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/RepositoriesPage.java 4 ●●● patch | view | raw | blame | history
src/com/gitblit/wicket/pages/RepositoryPage.java 16 ●●●●● patch | view | raw | blame | history
tmplt.pom.xml 7 ●●●●● patch | view | raw | blame | history
.gitignore
@@ -27,3 +27,4 @@
*.directory
/.gradle
/projects.conf
/pom.xml
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
pom.xml
New file
@@ -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>
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();
    }
}
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);
    }
}
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
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();
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));
        }
    }
}
}
tmplt.pom.xml
New file
@@ -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>