// Copyright (C) 2014 The Android Open Source Project // // 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.googlesource.gerrit.plugins.gitblit.auth; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.gitblit.Keys; import com.gitblit.manager.IPluginManager; import com.gitblit.manager.IRuntimeManager; import com.gitblit.manager.IUserManager; import com.gitblit.manager.RepositoryManager; import com.gitblit.models.RepositoryModel; import com.gitblit.models.UserModel; import com.gitblit.utils.CommitCache; import com.google.inject.Inject; import com.google.inject.Singleton; @Singleton public class GerritGitBlitRepositoryManager extends RepositoryManager { private static final Logger log = LoggerFactory.getLogger(GerritGitBlitRepositoryManager.class); private final IRuntimeManager runtimeManager; private final IUserManager userManager; @Inject public GerritGitBlitRepositoryManager(final IRuntimeManager runtimeManager, final IPluginManager pluginManager, final IUserManager userManager) { super(runtimeManager, pluginManager, userManager); this.runtimeManager = runtimeManager; this.userManager = userManager; } @Override public RepositoryModel getRepositoryModel(final UserModel user, final String repositoryName) { RepositoryModel repository = getRepositoryModel(repositoryName); if (repository != null) { // Fix for anonymous access. UserModel currentUser = (user instanceof GerritGitBlitUserModel) ? user : userManager.getUserModel(GerritGitBlitUserModel.ANONYMOUS_USER); if (currentUser.canView(repository)) { return repository; } } return null; } // Unfortunately, there is no similar method with user, repo, and branch here for branch visibility. That sits over on UserModel, and while we can // and do override that one, too, the UserModel.ANONYMOUS is a static final object of type UserClass, which leads to problems to properly implement // Gerrit's per-ref access rules that are difficult to overcome. // // The original Gerrit-GitBlit plugin ensured that view pages always required authentication, and somehow managed to provide a fake "$anonymous" // "authenticated" user to GitBlit if the user was not logged in to Gerrit. That fake user was a GerritGitBlitUserModel instance and thus obeyed // Gerrit's rules. However, with that approach I had some problems: // - it displays "$anonymous" as the username on the UI, which is ugly. // - it doesn't really work in all circumstances. I had cases where I had trouble after I had been logged in and then logged out via GitBlit's // logout. // - the "$anonymous" user has a "logout" menu item, which just doesn't make sense. // - one cannot log in via GitBlit, which makes deep links to GitBlit pages containing things the anonymous user cannot see fail unless the // person who visits the link happens to be logged in in Gerrit already. Which is kind of bad since GitBlit never shows any login form, // since there's always an "authenticated" user, either a real one or this fake "$anonymous" user. // - I never got that approach to work with GitBlit 1.6.0 at all, but that is in all likelihood my fault. // // Because of the above, I've opted for a somewhat different approach. All authentication goes via Gerrit. Log in logs you in to gerrit, log out // logs you out from Gerrit. Only real Gerrit users are ever logged in; if you're not logged in, you're really anonymous and not authenticated. I // redefine the UserModel.ANONYMOUS object to ensure that it is indeed a GerritGitBlitUserModel that does indeed query Gerrit for access // permissions. (Admittedly, that's a gruesome hack. It would have helped if the UserManager had a method getAnonymousUser() and that was used // consistently throughout GitBlit instead of these ubiquitous direct field accesses to UserModel.ANONYMOUS. Then I could just have overridden // that method.) // // As a result, login and logout work as expected, and if GitBlit is configured to allow anonymous viewing, non-logged-in (anonymous) users can // indeed only see what they're supposed to see and have to log-in otherwise. @Override public boolean deleteRepository(String repositoryName) { // Just to be sure. Shouldn't be called anyway. return true; } @Override public boolean deleteRepositoryModel(RepositoryModel model) { // Just to be sure. Shouldn't be called anyway. return true; } @Override protected void configureCommitCache() { int daysToCache = runtimeManager.getSettings().getInteger(Keys.web.activityCacheDays, 14); if (daysToCache <= 0) { log.info("Commit cache is disabled"); return; } CommitCache.instance().setCacheDays(daysToCache); // Run this potentially long-running operation in the background Thread loader = new Thread() { @Override public void run() { log.info("Starting to populate commit cache in background"); GerritGitBlitRepositoryManager.super.configureCommitCache(); log.info("Done populating commit cache in background"); } }; loader.setName("CommitCacheLoader"); loader.setDaemon(true); loader.start(); } }