James Moger
2011-10-01 ca9d0f3cb462e3ff9daa676c9f5e81407fbb79d6
Refactored servlet filters and now have authenticated RpcServlet.
2 files added
4 files modified
598 ■■■■■ changed files
src/WEB-INF/web.xml 16 ●●●●● patch | view | raw | blame | history
src/com/gitblit/AccessRestrictionFilter.java 221 ●●●● patch | view | raw | blame | history
src/com/gitblit/AuthenticationFilter.java 201 ●●●●● patch | view | raw | blame | history
src/com/gitblit/Constants.java 4 ●●●● patch | view | raw | blame | history
src/com/gitblit/RpcFilter.java 131 ●●●●● patch | view | raw | blame | history
src/com/gitblit/RpcServlet.java 25 ●●●● patch | view | raw | blame | history
src/WEB-INF/web.xml
@@ -127,7 +127,22 @@
        <filter-name>ZipFilter</filter-name>
        <url-pattern>/zip/*</url-pattern>
    </filter-mapping>
        
    <!-- Rpc Restriction Filter
         <url-pattern> MUST match:
            * RpcServlet
            * com.gitblit.Constants.RPC_PATH
            * Wicket Filter ignorePaths parameter -->
    <filter>
        <filter-name>RpcFilter</filter-name>
        <filter-class>com.gitblit.RpcFilter</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>RpcFilter</filter-name>
        <url-pattern>/rpc/*</url-pattern>
    </filter-mapping>
        
    <!-- Wicket Filter -->
    <filter>
@@ -152,6 +167,7 @@
                 * ZipServlet <url-pattern>
                 * com.gitblit.Constants.ZIP_PATH
                 * FederationServlet <url-pattern>
                 * RpcFilter <url-pattern>
                 * RpcServlet <url-pattern> -->
            <param-value>git/,feed/,zip/,federation/,rpc/</param-value>
        </init-param>
src/com/gitblit/AccessRestrictionFilter.java
@@ -16,34 +16,23 @@
package com.gitblit;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.Principal;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.eclipse.jgit.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.AuthenticationFilter.AuthenticatedRequest;
import com.gitblit.models.RepositoryModel;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
/**
 * The AccessRestrictionFilter is a servlet filter that preprocesses requests
 * that match its url pattern definition in the web.xml file.
 * The AccessRestrictionFilter is an AuthenticationFilter that confirms that the
 * requested repository can be accessed by the anonymous or named user.
 * 
 * The filter extracts the name of the repository from the url and determines if
 * the requested action for the repository requires a Basic authentication
@@ -55,19 +44,7 @@
 * @author James Moger
 * 
 */
public abstract class AccessRestrictionFilter implements Filter {
    private static final String BASIC = "Basic";
    private static final String CHALLENGE = BASIC + " realm=\"" + Constants.NAME + "\"";
    private static final String SESSION_SECURED = "com.gitblit.secured";
    protected transient Logger logger;
    public AccessRestrictionFilter() {
        logger = LoggerFactory.getLogger(getClass());
    }
public abstract class AccessRestrictionFilter extends AuthenticationFilter {
    /**
     * Extract the repository name from the url.
@@ -118,26 +95,7 @@
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        // Wrap the HttpServletRequest with the AccessRestrictionRequest which
        // overrides the servlet container user principal methods.
        // JGit requires either:
        //
        // 1. servlet container authenticated user
        // 2. http.receivepack = true in each repository's config
        //
        // Gitblit must conditionally authenticate users per-repository so just
        // enabling http.receivepack is insufficient.
        AccessRestrictionRequest accessRequest = new AccessRestrictionRequest(httpRequest);
        String servletUrl = httpRequest.getContextPath() + httpRequest.getServletPath();
        String url = httpRequest.getRequestURI().substring(servletUrl.length());
        String params = httpRequest.getQueryString();
        if (url.length() > 0 && url.charAt(0) == '/') {
            url = url.substring(1);
        }
        String fullUrl = url + (StringUtils.isEmpty(params) ? "" : ("?" + params));
        String fullUrl = getFullUrl(httpRequest);
        String repository = extractRepositoryName(fullUrl);
        // Determine if the request URL is restricted
@@ -148,145 +106,64 @@
        RepositoryModel model = GitBlit.self().getRepositoryModel(repository);
        if (model == null) {
            // repository not found. send 404.
            logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_NOT_FOUND + ")");
            logger.info(MessageFormat.format("ARF: {0} ({1})", fullUrl,
                    HttpServletResponse.SC_NOT_FOUND));
            httpResponse.sendError(HttpServletResponse.SC_NOT_FOUND);
            return;
        }
        // Wrap the HttpServletRequest with the AccessRestrictionRequest which
        // overrides the servlet container user principal methods.
        // JGit requires either:
        //
        // 1. servlet container authenticated user
        // 2. http.receivepack = true in each repository's config
        //
        // Gitblit must conditionally authenticate users per-repository so just
        // enabling http.receivepack is insufficient.
        AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(httpRequest);
        UserModel user = getUser(httpRequest);
        if (user != null) {
            authenticatedRequest.setUser(user);
        }
        // BASIC authentication challenge and response processing
        if (!StringUtils.isEmpty(urlRequestType) && requiresAuthentication(model)) {
            // look for client authorization credentials in header
            final String authorization = httpRequest.getHeader("Authorization");
            if (authorization != null && authorization.startsWith(BASIC)) {
                // Authorization: Basic base64credentials
                String base64Credentials = authorization.substring(BASIC.length()).trim();
                String credentials = new String(Base64.decode(base64Credentials),
                        Charset.forName("UTF-8"));
                // credentials = username:password
                final String[] values = credentials.split(":");
                if (values.length == 2) {
                    String username = values[0];
                    char[] password = values[1].toCharArray();
                    UserModel user = GitBlit.self().authenticate(username, password);
                    if (user != null) {
                        accessRequest.setUser(user);
                        if (user.canAdmin || canAccess(model, user, urlRequestType)) {
                            // authenticated request permitted.
                            // pass processing to the restricted servlet.
                            newSession(accessRequest, httpResponse);
                            logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_CONTINUE
                                    + ") authenticated");
                            chain.doFilter(accessRequest, httpResponse);
                            return;
                        }
                        // valid user, but not for requested access. send 403.
                        if (GitBlit.isDebugMode()) {
                            logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_FORBIDDEN
                                    + ")");
                            logger.info(MessageFormat.format("AUTH: {0} forbidden to access {1}",
                                    user.username, url));
                        }
                        httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
                        return;
                    }
                }
            if (user == null) {
                // challenge client to provide credentials. send 401.
                if (GitBlit.isDebugMode()) {
                    logger.info(MessageFormat
                            .format("AUTH: invalid credentials ({0})", credentials));
                    logger.info(MessageFormat.format("ARF: CHALLENGE {0}", fullUrl));
                }
                httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
                httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
                return;
            } else {
                // check user access for request
                if (user.canAdmin || canAccess(model, user, urlRequestType)) {
                    // authenticated request permitted.
                    // pass processing to the restricted servlet.
                    newSession(authenticatedRequest, httpResponse);
                    logger.info(MessageFormat.format("ARF: {0} ({1}) authenticated", fullUrl,
                            HttpServletResponse.SC_CONTINUE));
                    chain.doFilter(authenticatedRequest, httpResponse);
                    return;
                }
                // valid user, but not for requested access. send 403.
                if (GitBlit.isDebugMode()) {
                    logger.info(MessageFormat.format("ARF: {0} forbidden to access {1}",
                            user.username, fullUrl));
                }
                httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
                return;
            }
            // challenge client to provide credentials. send 401.
            if (GitBlit.isDebugMode()) {
                logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_UNAUTHORIZED + ")");
                logger.info("AUTH: Challenge " + CHALLENGE);
            }
            httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
            httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
            return;
        }
        if (GitBlit.isDebugMode()) {
            logger.info("ARF: " + fullUrl + " (" + HttpServletResponse.SC_CONTINUE
                    + ") unauthenticated");
            logger.info(MessageFormat.format("ARF: {0} ({1}) unauthenticated", fullUrl,
                    HttpServletResponse.SC_CONTINUE));
        }
        // unauthenticated request permitted.
        // pass processing to the restricted servlet.
        chain.doFilter(accessRequest, httpResponse);
    }
    /**
     * Taken from Jetty's LoginAuthenticator.renewSessionOnAuthentication()
     */
    protected void newSession(HttpServletRequest request, HttpServletResponse response) {
        HttpSession oldSession = request.getSession(false);
        if (oldSession != null && oldSession.getAttribute(SESSION_SECURED) == null) {
            synchronized (this) {
                Map<String, Object> attributes = new HashMap<String, Object>();
                Enumeration<String> e = oldSession.getAttributeNames();
                while (e.hasMoreElements()) {
                    String name = e.nextElement();
                    attributes.put(name, oldSession.getAttribute(name));
                    oldSession.removeAttribute(name);
                }
                oldSession.invalidate();
                HttpSession newSession = request.getSession(true);
                newSession.setAttribute(SESSION_SECURED, Boolean.TRUE);
                for (Map.Entry<String, Object> entry : attributes.entrySet()) {
                    newSession.setAttribute(entry.getKey(), entry.getValue());
                }
            }
        }
    }
    /**
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     */
    @Override
    public void init(final FilterConfig config) throws ServletException {
    }
    /**
     * @see javax.servlet.Filter#destroy()
     */
    @Override
    public void destroy() {
    }
    /**
     * Wraps a standard HttpServletRequest and overrides user principal methods.
     */
    public static class AccessRestrictionRequest extends ServletRequestWrapper {
        private UserModel user;
        public AccessRestrictionRequest(HttpServletRequest req) {
            super(req);
            user = new UserModel("anonymous");
        }
        void setUser(UserModel user) {
            this.user = user;
        }
        @Override
        public String getRemoteUser() {
            return user.username;
        }
        @Override
        public boolean isUserInRole(String role) {
            if (role.equals(Constants.ADMIN_ROLE)) {
                return user.canAdmin;
            }
            return user.canAccessRepository(role);
        }
        @Override
        public Principal getUserPrincipal() {
            return user;
        }
        chain.doFilter(authenticatedRequest, httpResponse);
    }
}
src/com/gitblit/AuthenticationFilter.java
New file
@@ -0,0 +1,201 @@
/*
 * Copyright 2011 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit;
import java.io.IOException;
import java.nio.charset.Charset;
import java.security.Principal;
import java.text.MessageFormat;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.eclipse.jgit.util.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.gitblit.models.UserModel;
import com.gitblit.utils.StringUtils;
/**
 * The AuthenticationFilter is a servlet filter that preprocesses requests that
 * match its url pattern definition in the web.xml file.
 *
 * http://en.wikipedia.org/wiki/Basic_access_authentication
 *
 * @author James Moger
 *
 */
public abstract class AuthenticationFilter implements Filter {
    protected static final String BASIC = "Basic";
    protected static final String CHALLENGE = BASIC + " realm=\"" + Constants.NAME + "\"";
    protected static final String SESSION_SECURED = "com.gitblit.secured";
    protected transient Logger logger = LoggerFactory.getLogger(getClass());
    /**
     * doFilter does the actual work of preprocessing the request to ensure that
     * the user may proceed.
     *
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
     *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public abstract void doFilter(final ServletRequest request, final ServletResponse response,
            final FilterChain chain) throws IOException, ServletException;
    /**
     * Returns the full relative url of the request.
     *
     * @param httpRequest
     * @return url
     */
    protected String getFullUrl(HttpServletRequest httpRequest) {
        String servletUrl = httpRequest.getContextPath() + httpRequest.getServletPath();
        String url = httpRequest.getRequestURI().substring(servletUrl.length());
        String params = httpRequest.getQueryString();
        if (url.length() > 0 && url.charAt(0) == '/') {
            url = url.substring(1);
        }
        String fullUrl = url + (StringUtils.isEmpty(params) ? "" : ("?" + params));
        return fullUrl;
    }
    /**
     * Returns the user making the request, if the user has authenticated.
     *
     * @param httpRequest
     * @return user
     */
    protected UserModel getUser(HttpServletRequest httpRequest) {
        UserModel user = null;
        // look for client authorization credentials in header
        final String authorization = httpRequest.getHeader("Authorization");
        if (authorization != null && authorization.startsWith(BASIC)) {
            // Authorization: Basic base64credentials
            String base64Credentials = authorization.substring(BASIC.length()).trim();
            String credentials = new String(Base64.decode(base64Credentials),
                    Charset.forName("UTF-8"));
            // credentials = username:password
            final String[] values = credentials.split(":");
            if (values.length == 2) {
                String username = values[0];
                char[] password = values[1].toCharArray();
                user = GitBlit.self().authenticate(username, password);
                if (user != null) {
                    return user;
                }
            }
            if (GitBlit.isDebugMode()) {
                logger.info(MessageFormat.format("AUTH: invalid credentials ({0})", credentials));
            }
        }
        return null;
    }
    /**
     * Taken from Jetty's LoginAuthenticator.renewSessionOnAuthentication()
     */
    @SuppressWarnings("unchecked")
    protected void newSession(HttpServletRequest request, HttpServletResponse response) {
        HttpSession oldSession = request.getSession(false);
        if (oldSession != null && oldSession.getAttribute(SESSION_SECURED) == null) {
            synchronized (this) {
                Map<String, Object> attributes = new HashMap<String, Object>();
                Enumeration<String> e = oldSession.getAttributeNames();
                while (e.hasMoreElements()) {
                    String name = e.nextElement();
                    attributes.put(name, oldSession.getAttribute(name));
                    oldSession.removeAttribute(name);
                }
                oldSession.invalidate();
                HttpSession newSession = request.getSession(true);
                newSession.setAttribute(SESSION_SECURED, Boolean.TRUE);
                for (Map.Entry<String, Object> entry : attributes.entrySet()) {
                    newSession.setAttribute(entry.getKey(), entry.getValue());
                }
            }
        }
    }
    /**
     * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
     */
    @Override
    public void init(final FilterConfig config) throws ServletException {
    }
    /**
     * @see javax.servlet.Filter#destroy()
     */
    @Override
    public void destroy() {
    }
    /**
     * Wraps a standard HttpServletRequest and overrides user principal methods.
     */
    public static class AuthenticatedRequest extends ServletRequestWrapper {
        private UserModel user;
        public AuthenticatedRequest(HttpServletRequest req) {
            super(req);
            user = new UserModel("anonymous");
        }
        UserModel getUser() {
            return user;
        }
        void setUser(UserModel user) {
            this.user = user;
        }
        @Override
        public String getRemoteUser() {
            return user.username;
        }
        @Override
        public boolean isUserInRole(String role) {
            if (role.equals(Constants.ADMIN_ROLE)) {
                return user.canAdmin;
            }
            return user.canAccessRepository(role);
        }
        @Override
        public Principal getUserPrincipal() {
            return user;
        }
    }
}
src/com/gitblit/Constants.java
@@ -213,6 +213,10 @@
            return LIST_REPOSITORIES;
        }
        
        public boolean exceeds(RpcRequest type) {
            return this.ordinal() > type.ordinal();
        }
        @Override
        public String toString() {
            return name();
src/com/gitblit/RpcFilter.java
New file
@@ -0,0 +1,131 @@
/*
 * Copyright 2011 gitblit.com.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gitblit;
import java.io.IOException;
import java.text.MessageFormat;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.gitblit.Constants.RpcRequest;
import com.gitblit.models.UserModel;
/**
 * The RpcFilter is a servlet filter that secures the RpcServlet.
 *
 * The filter extracts the rpc request type from the url and determines if the
 * requested action requires a Basic authentication prompt. If authentication is
 * required and no credentials are stored in the "Authorization" header, then a
 * basic authentication challenge is issued.
 *
 * http://en.wikipedia.org/wiki/Basic_access_authentication
 *
 * @author James Moger
 *
 */
public class RpcFilter extends AuthenticationFilter {
    /**
     * doFilter does the actual work of preprocessing the request to ensure that
     * the user may proceed.
     *
     * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest,
     *      javax.servlet.ServletResponse, javax.servlet.FilterChain)
     */
    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
            final FilterChain chain) throws IOException, ServletException {
        HttpServletRequest httpRequest = (HttpServletRequest) request;
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        if (!GitBlit.getBoolean(Keys.web.enableRpcServlet, false)) {
            logger.warn(Keys.web.enableRpcServlet + " must be set TRUE for rpc requests.");
            httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
            return;
        }
        String fullUrl = getFullUrl(httpRequest);
        RpcRequest requestType = RpcRequest.fromName(httpRequest.getParameter("req"));
        boolean adminRequest = requestType.exceeds(RpcRequest.LIST_REPOSITORIES);
        boolean authenticateView = GitBlit.getBoolean(Keys.web.authenticateViewPages, false);
        boolean authenticateAdmin = GitBlit.getBoolean(Keys.web.authenticateAdminPages, true);
        // Wrap the HttpServletRequest with the RpcServletnRequest which
        // overrides the servlet container user principal methods.
        AuthenticatedRequest authenticatedRequest = new AuthenticatedRequest(httpRequest);
        UserModel user = getUser(httpRequest);
        if (user != null) {
            authenticatedRequest.setUser(user);
        }
        // BASIC authentication challenge and response processing
        if ((adminRequest && authenticateAdmin) || (!adminRequest && authenticateView)) {
            if (user == null) {
                // challenge client to provide credentials. send 401.
                if (GitBlit.isDebugMode()) {
                    logger.info(MessageFormat.format("RPC: CHALLENGE {0}", fullUrl));
                }
                httpResponse.setHeader("WWW-Authenticate", CHALLENGE);
                httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED);
                return;
            } else {
                // check user access for request
                if (user.canAdmin || canAccess(user, requestType)) {
                    // authenticated request permitted.
                    // pass processing to the restricted servlet.
                    newSession(authenticatedRequest, httpResponse);
                    logger.info(MessageFormat.format("RPC: {0} ({1}) authenticated", fullUrl,
                            HttpServletResponse.SC_CONTINUE));
                    chain.doFilter(authenticatedRequest, httpResponse);
                    return;
                }
                // valid user, but not for requested access. send 403.
                if (GitBlit.isDebugMode()) {
                    logger.info(MessageFormat.format("RPC: {0} forbidden to access {1}",
                            user.username, fullUrl));
                }
                httpResponse.sendError(HttpServletResponse.SC_FORBIDDEN);
                return;
            }
        }
        if (GitBlit.isDebugMode()) {
            logger.info(MessageFormat.format("RPC: {0} ({1}) unauthenticated", fullUrl,
                    HttpServletResponse.SC_CONTINUE));
        }
        // unauthenticated request permitted.
        // pass processing to the restricted servlet.
        chain.doFilter(authenticatedRequest, httpResponse);
    }
    private boolean canAccess(UserModel user, RpcRequest requestType) {
        switch (requestType) {
        case LIST_REPOSITORIES:
            return true;
        default:
            return user.canAdmin;
        }
    }
}
src/com/gitblit/RpcServlet.java
@@ -15,12 +15,15 @@
 */
package com.gitblit;
import java.io.IOException;
import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.gitblit.Constants.RpcRequest;
@@ -51,26 +54,16 @@
     * @throws java.io.IOException
     */
    @Override
    protected void processRequest(javax.servlet.http.HttpServletRequest request,
            javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException,
            java.io.IOException {
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        RpcRequest reqType = RpcRequest.fromName(request.getParameter("req"));
        logger.info(MessageFormat.format("Rpc {0} request from {1}", reqType,
                request.getRemoteAddr()));
        if (!GitBlit.getBoolean(Keys.web.enableRpcServlet, false)) {
            logger.warn(Keys.web.enableRpcServlet + " must be set TRUE for rpc requests.");
            response.sendError(HttpServletResponse.SC_FORBIDDEN);
            return;
        }
        // TODO user authentication and authorization
        UserModel user = null;
        UserModel user = (UserModel) request.getUserPrincipal();
        Object result = null;
        if (RpcRequest.LIST_REPOSITORIES.equals(reqType)) {
            // list repositories
            // Determine the Gitblit clone url
            String gitblitUrl = HttpUtils.getGitblitURL(request);
            StringBuilder sb = new StringBuilder();
@@ -79,6 +72,7 @@
            sb.append("{0}");
            String cloneUrl = sb.toString();
            // list repositories
            List<RepositoryModel> list = GitBlit.self().getRepositoryModels(user);
            Map<String, RepositoryModel> repositories = new HashMap<String, RepositoryModel>();
            for (RepositoryModel model : list) {
@@ -88,11 +82,6 @@
            result = repositories;
        } else if (RpcRequest.LIST_USERS.equals(reqType)) {
            // list users
            if (user == null || !user.canAdmin) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN);
                return;
            }
            // user is authorized to retrieve all accounts
            List<String> names = GitBlit.self().getAllUsernames();
            List<UserModel> users = new ArrayList<UserModel>();
            for (String name : names) {