Merge branch 'stable-2.15' into stable-2.16

* stable-2.15:
  LfsLocksAction: Use Logger's built-in string formatting

Change-Id: I58a89e20b49cc3fefeaf58b1d19c8ac16eee5835
diff --git a/BUILD b/BUILD
index aac05ab..2f873b7 100644
--- a/BUILD
+++ b/BUILD
@@ -40,5 +40,6 @@
     exports = PLUGIN_DEPS + PLUGIN_TEST_DEPS + [
         ":lfs__plugin",
         "@jgit-lfs//jar",
+        "@joda-time//jar",
     ],
 )
diff --git a/WORKSPACE b/WORKSPACE
index e338fee..bbb161e 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -3,7 +3,7 @@
 load("//:bazlets.bzl", "load_bazlets")
 
 load_bazlets(
-    commit = "8386b3fbf80e375f0a10c8386c0a8dfe260c5c1b",
+    commit = "c827ba79413585ab9dfc1bbd0d7f609eedd6aa80",
     #local_path = "/home/<user>/projects/bazlets",
 )
 
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl
index aff59ef..f9c5ae7 100644
--- a/external_plugin_deps.bzl
+++ b/external_plugin_deps.bzl
@@ -1,13 +1,13 @@
 load("//tools/bzl:maven_jar.bzl", "GERRIT", "MAVEN_CENTRAL", "MAVEN_LOCAL", "maven_jar")
 
-JGIT_VERSION = "4.9.8.201812241815-r"
+JGIT_VERSION = "5.1.3.201810200350-r"
 REPO = MAVEN_CENTRAL
 
 def external_plugin_deps():
     maven_jar(
         name = "jgit-http-apache",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.http.apache:" + JGIT_VERSION,
-        sha1 = "a33c9029a6ed9b0b476d0763da38d9b4ba3a0a7a",
+        sha1 = "d98ca013eb8159b369af99e28be8b96a651c4f79",
         repository = REPO,
         unsign = True,
         exclude = [
@@ -19,7 +19,7 @@
     maven_jar(
         name = "jgit-lfs",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.lfs:" + JGIT_VERSION,
-        sha1 = "081d5d72d927fa5897ae0bbba72fa7522d502130",
+        sha1 = "9fa727360ff65f0443684a78dfc3a099da70a4f2",
         repository = REPO,
         unsign = True,
         exclude = [
@@ -31,7 +31,7 @@
     maven_jar(
         name = "jgit-lfs-server",
         artifact = "org.eclipse.jgit:org.eclipse.jgit.lfs.server:" + JGIT_VERSION,
-        sha1 = "d12cdeb61eff7f7ce43de403fadc8a378f7d4726",
+        sha1 = "8655240c3cf005ff22b7da95c2f1f1b23dc746c5",
         repository = REPO,
         unsign = True,
         exclude = [
@@ -39,3 +39,9 @@
             "plugin.properties",
         ],
     )
+
+    maven_jar(
+        name = "joda-time",
+        artifact = "joda-time:joda-time:2.9.9",
+        sha1 = "f7b520c458572890807d143670c9b24f4de90897",
+    )
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java
index d5eeddc..bbd97d5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java
@@ -19,15 +19,14 @@
 import static com.google.gerrit.extensions.client.ProjectState.HIDDEN;
 import static com.google.gerrit.extensions.client.ProjectState.READ_ONLY;
 import static com.google.gerrit.server.permissions.ProjectPermission.ACCESS;
+import static com.google.gerrit.server.permissions.ProjectPermission.PUSH_AT_LEAST_ONE_REF;
 
-import com.google.common.base.Strings;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.common.ProjectUtil;
-import com.google.gerrit.common.data.Capable;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -42,15 +41,13 @@
 import org.eclipse.jgit.lfs.server.LargeFileRepository;
 import org.eclipse.jgit.lfs.server.LfsObject;
 import org.eclipse.jgit.lfs.server.LfsProtocolServlet;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Singleton
 public class LfsApiServlet extends LfsProtocolServlet {
   public static final String LFS_OBJECTS_REGEX_REST =
       String.format(LFS_URL_REGEX_TEMPLATE, LFS_OBJECTS_PATH);
 
-  private static final Logger log = LoggerFactory.getLogger(LfsApiServlet.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
   private static final long serialVersionUID = 1L;
   private static final Pattern URL_PATTERN = Pattern.compile(LFS_OBJECTS_REGEX_REST);
 
@@ -125,18 +122,19 @@
 
   private void authorizeUser(CurrentUser user, ProjectState state, LfsRequest request)
       throws LfsUnauthorized {
-    ProjectControl control = state.controlFor(user);
+    Project.NameKey projectName = state.getNameKey();
     if ((request.isDownload()
+            && !permissionBackend.user(user).project(projectName).testOrFalse(ACCESS))
+        || (request.isUpload()
             && !permissionBackend
                 .user(user)
-                .project(state.getProject().getNameKey())
-                .testOrFalse(ACCESS))
-        || (request.isUpload() && Capable.OK != control.canPushToAtLeastOneRef())) {
+                .project(projectName)
+                .testOrFalse(PUSH_AT_LEAST_ONE_REF))) {
       String op = request.getOperation().toLowerCase();
       String project = state.getProject().getName();
-      String userName =
-          Strings.isNullOrEmpty(user.getUserName()) ? "anonymous" : user.getUserName();
-      log.debug("operation {} unauthorized for user {} on project {}", op, userName, project);
+      String userName = user.getUserName().orElse("anonymous");
+      log.atFine().log(
+          "operation %s unauthorized for user %s on project %s", op, userName, project);
       throw new LfsUnauthorized(op, project);
     }
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java
index 909d295..a603705 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java
@@ -23,7 +23,6 @@
 public abstract class LfsAuthToken {
   public abstract static class Processor<T extends LfsAuthToken> {
     private static final char DELIMETER = '~';
-
     protected final LfsCipher cipher;
 
     protected Processor(LfsCipher cipher) {
@@ -39,7 +38,6 @@
       if (!decrypted.isPresent()) {
         return Optional.empty();
       }
-
       return createToken(Splitter.on(DELIMETER).splitToList(decrypted.get()));
     }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthUserProvider.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthUserProvider.java
index f7d3078..fdb89b5 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthUserProvider.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthUserProvider.java
@@ -55,9 +55,9 @@
           sshAuth.getUserFromValidToken(
               auth.substring(SSH_AUTH_PREFIX.length()), project, operation);
       if (user.isPresent()) {
-        AccountState acc = accounts.getByUsername(user.get());
-        if (acc != null) {
-          return userFactory.create(acc);
+        Optional<AccountState> acc = accounts.getByUsername(user.get());
+        if (acc.isPresent()) {
+          return userFactory.create(acc.get());
         }
       }
     }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsCipher.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsCipher.java
index aec332a..2f97695 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsCipher.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsCipher.java
@@ -17,6 +17,7 @@
 import static java.nio.charset.StandardCharsets.UTF_8;
 
 import com.google.common.base.Strings;
+import com.google.common.flogger.FluentLogger;
 import com.google.common.primitives.Bytes;
 import com.google.inject.Singleton;
 import java.security.AlgorithmParameters;
@@ -30,12 +31,10 @@
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
 import org.eclipse.jgit.util.Base64;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Singleton
 public class LfsCipher {
-  private static final Logger log = LoggerFactory.getLogger(LfsCipher.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
   private static final int IV_LENGTH = 16;
   private static final String ALGORITHM = "AES";
   private static final String CIPHER_TYPE = ALGORITHM + "/CBC/PKCS5PADDING";
@@ -56,7 +55,7 @@
       Cipher cipher = cipher(initVector, Cipher.ENCRYPT_MODE);
       return Base64.encodeBytes(Bytes.concat(initVector, cipher.doFinal(input.getBytes(UTF_8))));
     } catch (GeneralSecurityException e) {
-      log.error("Token generation failed with error", e);
+      log.atSevere().withCause(e).log("Token generation failed with error");
       throw new RuntimeException(e);
     }
   }
@@ -73,7 +72,7 @@
       return Optional.of(
           new String(cipher.doFinal(Arrays.copyOfRange(bytes, IV_LENGTH, bytes.length)), UTF_8));
     } catch (GeneralSecurityException e) {
-      log.error("Exception was thrown during token verification", e);
+      log.atSevere().withCause(e).log("Exception was thrown during token verification");
     }
 
     return Optional.empty();
@@ -94,7 +93,7 @@
       generator.init(KEY_SIZE, random);
       return generator.generateKey();
     } catch (NoSuchAlgorithmException e) {
-      log.error("Generating key failed with error", e);
+      log.atSevere().withCause(e).log("Generating key failed with error");
       throw new RuntimeException(e);
     }
   }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsProjectsConfig.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsProjectsConfig.java
index 390a65f..ea5e076 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsProjectsConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsProjectsConfig.java
@@ -21,7 +21,7 @@
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.git.VersionedMetaData;
+import com.google.gerrit.server.git.meta.VersionedMetaData;
 import com.google.gerrit.server.project.ProjectCache;
 import java.io.IOException;
 import java.util.ArrayList;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsRepositoryResolver.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsRepositoryResolver.java
index 3e97db3..59cdb13 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsRepositoryResolver.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsRepositoryResolver.java
@@ -15,16 +15,15 @@
 package com.googlesource.gerrit.plugins.lfs;
 
 import com.google.common.base.Strings;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.inject.Inject;
 import java.util.Map;
 import org.eclipse.jgit.lfs.errors.LfsRepositoryNotFound;
 import org.eclipse.jgit.lfs.server.LargeFileRepository;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 public class LfsRepositoryResolver {
-  private static final Logger log = LoggerFactory.getLogger(LfsRepositoryResolver.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
 
   private final LfsRepositoriesCache cache;
   private final LfsBackend defaultBackend;
@@ -47,7 +46,8 @@
     } else {
       backend = backends.get(backendName);
       if (backend == null) {
-        log.error("Project {} is configured with not existing backend {}", project, backendName);
+        log.atSevere().log(
+            "Project %s is configured with not existing backend %s", project, backendName);
         throw new LfsRepositoryNotFound(project.get());
       }
     }
@@ -58,11 +58,9 @@
     }
 
     // this is unlikely situation as cache is pre-populated from config but...
-    log.error(
-        "Project {} is configured with not existing backend {} of type {}",
-        project,
-        backend.name(),
-        backend.type);
+    log.atSevere().log(
+        "Project %s is configured with not existing backend %s of type %s",
+        project, backend.name(), backend.type);
     throw new LfsRepositoryNotFound(project.get());
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java
index 12c5552..266d8d0 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java
@@ -14,6 +14,7 @@
 
 package com.googlesource.gerrit.plugins.lfs;
 
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.server.CurrentUser;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
@@ -21,8 +22,6 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Optional;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Singleton
 class LfsSshRequestAuthorizer {
@@ -32,10 +31,9 @@
     }
   }
 
-  private static final Logger log = LoggerFactory.getLogger(LfsSshRequestAuthorizer.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
   private static final int DEFAULT_SSH_TIMEOUT = 10;
   static final String SSH_AUTH_PREFIX = "Ssh: ";
-
   private final Processor processor;
   private final Long expiresIn;
 
@@ -49,17 +47,16 @@
               .getGlobalConfig()
               .getInt("auth", null, "sshExpirationSeconds", DEFAULT_SSH_TIMEOUT);
     } catch (IllegalArgumentException e) {
-      log.warn(
-          "Reading expiration timeout failed with error." + " Falling back to default {}",
-          DEFAULT_SSH_TIMEOUT,
-          e);
+      log.atWarning().withCause(e).log(
+          "Reading expiration timeout failed with error. Falling back to default %d",
+          DEFAULT_SSH_TIMEOUT);
     }
     this.expiresIn = timeout;
   }
 
   SshAuthInfo generateAuthInfo(CurrentUser user, String project, String operation) {
     LfsSshAuthToken token =
-        new LfsSshAuthToken(user.getUserName(), project, operation, Instant.now(), expiresIn);
+        new LfsSshAuthToken(user.getUserName().get(), project, operation, Instant.now(), expiresIn);
     return new SshAuthInfo(processor.serialize(token), token.issued, token.expiresIn);
   }
 
@@ -68,13 +65,11 @@
     if (!token.isPresent()) {
       return Optional.empty();
     }
-
     Verifier verifier = new Verifier(token.get(), project, operation);
     if (!verifier.verify()) {
-      log.error("Invalid data was provided with auth token {}.", authToken);
+      log.atSevere().log("Invalid data was provided with auth token %s.", authToken);
       return Optional.empty();
     }
-
     return Optional.of(token.get().user);
   }
 
@@ -100,7 +95,6 @@
       if (values.size() != 5) {
         return Optional.empty();
       }
-
       return Optional.of(
           new LfsSshAuthToken(
               values.get(0),
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/Lifecycle.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/Lifecycle.java
index ec386f1..90347be 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/Lifecycle.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/Lifecycle.java
@@ -15,18 +15,17 @@
 package com.googlesource.gerrit.plugins.lfs;
 
 import com.google.common.base.Strings;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.extensions.annotations.PluginName;
 import com.google.gerrit.extensions.events.LifecycleListener;
 import com.google.gerrit.server.config.GerritServerConfig;
 import com.google.inject.Inject;
 import com.google.inject.Singleton;
 import org.eclipse.jgit.lib.Config;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Singleton
 public class Lifecycle implements LifecycleListener {
-  private static final Logger log = LoggerFactory.getLogger(Lifecycle.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
 
   private final String name;
   private final Config config;
@@ -48,11 +47,10 @@
   }
 
   private void warn(String msg) {
-    log.warn(
-        "{}; LFS will not be enabled. Run site initialization, or manually set"
-            + " lfs.plugin to '{}' in gerrit.config",
-        msg,
-        name);
+    log.atWarning().log(
+        "%s; LFS will not be enabled. Run site initialization, or manually set"
+            + " lfs.plugin to '%s' in gerrit.config",
+        msg, name);
   }
 
   @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/PutLfsGlobalConfig.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/PutLfsGlobalConfig.java
index 5b0468f..7ebd1ef 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/PutLfsGlobalConfig.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/PutLfsGlobalConfig.java
@@ -30,7 +30,7 @@
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.IdentifiedUser;
 import com.google.gerrit.server.config.AllProjectsName;
-import com.google.gerrit.server.git.MetaDataUpdate;
+import com.google.gerrit.server.git.meta.MetaDataUpdate;
 import com.google.gerrit.server.permissions.PermissionBackend;
 import com.google.gerrit.server.project.ProjectResource;
 import com.google.inject.Inject;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizer.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizer.java
index 7e982b5..1336884 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizer.java
@@ -47,7 +47,6 @@
     if (!token.isPresent()) {
       return false;
     }
-
     return new Verifier(token.get(), operation, id).verify();
   }
 
@@ -72,7 +71,6 @@
       if (values.size() != 4) {
         return Optional.empty();
       }
-
       return Optional.of(
           new LfsFsAuthToken(
               values.get(0),
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsGetLocksAction.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsGetLocksAction.java
index 32616f6..b730624 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsGetLocksAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsGetLocksAction.java
@@ -23,9 +23,9 @@
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackend.ForProject;
 import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
@@ -34,7 +34,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.eclipse.jgit.lfs.errors.LfsException;
-import org.eclipse.jgit.lfs.errors.LfsUnauthorized;
 
 public class LfsGetLocksAction extends LfsLocksAction {
   interface Factory extends LfsLocksAction.Factory<LfsGetLocksAction> {}
@@ -42,8 +41,6 @@
   static final Pattern LFS_LOCKS_URL_PATTERN =
       Pattern.compile(String.format(LFS_URL_REGEX_TEMPLATE, LFS_LOCKS_PATH_REGEX));
 
-  private final PermissionBackend permissionBackend;
-
   @Inject
   LfsGetLocksAction(
       PermissionBackend permissionBackend,
@@ -51,8 +48,7 @@
       LfsAuthUserProvider userProvider,
       LfsLocksHandler handler,
       @Assisted LfsLocksContext context) {
-    super(projectCache, userProvider, handler, context);
-    this.permissionBackend = permissionBackend;
+    super(permissionBackend, projectCache, userProvider, handler, context);
   }
 
   @Override
@@ -66,15 +62,14 @@
   }
 
   @Override
-  protected void authorizeUser(ProjectControl control) throws LfsUnauthorized {
-    try {
-      permissionBackend
-          .user(control.getUser())
-          .project(control.getProject().getNameKey())
-          .check(ACCESS);
-    } catch (AuthException | PermissionBackendException e) {
-      throwUnauthorizedOp("list locks", control);
-    }
+  protected void authorizeUser(ForProject project)
+      throws AuthException, PermissionBackendException {
+    project.check(ACCESS);
+  }
+
+  @Override
+  protected String getAction() {
+    return "list-locks";
   }
 
   @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksAction.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksAction.java
index 4fa8680..020c0c3 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksAction.java
@@ -21,12 +21,15 @@
 import static org.apache.http.HttpStatus.SC_UNAUTHORIZED;
 import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION;
 
-import com.google.common.base.Strings;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.common.ProjectUtil;
+import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackend.ForProject;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.ProjectState;
 import com.googlesource.gerrit.plugins.lfs.LfsAuthUserProvider;
 import com.googlesource.gerrit.plugins.lfs.locks.LfsLocksHandler.LfsLockExistsException;
@@ -34,15 +37,13 @@
 import org.eclipse.jgit.lfs.errors.LfsException;
 import org.eclipse.jgit.lfs.errors.LfsRepositoryNotFound;
 import org.eclipse.jgit.lfs.errors.LfsUnauthorized;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 abstract class LfsLocksAction {
   interface Factory<T extends LfsLocksAction> {
     T create(LfsLocksContext context);
   }
 
-  private static final Logger log = LoggerFactory.getLogger(LfsLocksAction.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
   /** Git LFS client uses 'upload' operation to authorize SSH Lock requests */
   private static final String LFS_LOCKING_OPERATION = "upload";
 
@@ -50,12 +51,15 @@
   protected final LfsAuthUserProvider userProvider;
   protected final LfsLocksHandler handler;
   protected final LfsLocksContext context;
+  protected final PermissionBackend permissionBackend;
 
   protected LfsLocksAction(
+      PermissionBackend permissionBackend,
       ProjectCache projectCache,
       LfsAuthUserProvider userProvider,
       LfsLocksHandler handler,
       LfsLocksContext context) {
+    this.permissionBackend = permissionBackend;
     this.projectCache = projectCache;
     this.userProvider = userProvider;
     this.handler = handler;
@@ -67,8 +71,12 @@
       String name = getProjectName();
       ProjectState project = getProject(name);
       CurrentUser user = getUser(name);
-      ProjectControl control = project.controlFor(user);
-      authorizeUser(control);
+      ProjectState state = projectCache.checkedGet(project.getNameKey());
+      try {
+        authorizeUser(permissionBackend.user(user).project(state.getNameKey()));
+      } catch (AuthException | PermissionBackendException e) {
+        throwUnauthorizedOp(getAction(), project, user);
+      }
       doRun(project, user);
     } catch (LfsUnauthorized e) {
       context.sendError(SC_UNAUTHORIZED, e.getMessage());
@@ -83,7 +91,10 @@
 
   protected abstract String getProjectName() throws LfsException;
 
-  protected abstract void authorizeUser(ProjectControl control) throws LfsUnauthorized;
+  protected abstract String getAction();
+
+  protected abstract void authorizeUser(ForProject project)
+      throws AuthException, PermissionBackendException;
 
   protected abstract void doRun(ProjectState project, CurrentUser user)
       throws LfsException, IOException;
@@ -102,13 +113,11 @@
         context.getHeader(HDR_AUTHORIZATION), project, LFS_LOCKING_OPERATION);
   }
 
-  protected void throwUnauthorizedOp(String op, ProjectControl control) throws LfsUnauthorized {
-    String project = control.getProject().getName();
-    String userName =
-        Strings.isNullOrEmpty(control.getUser().getUserName())
-            ? "anonymous"
-            : control.getUser().getUserName();
-    log.debug("operation {} unauthorized for user {} on project {}", op, userName, project);
+  private void throwUnauthorizedOp(String op, ProjectState state, CurrentUser user)
+      throws LfsUnauthorized {
+    String project = state.getProject().getName();
+    String userName = user.getUserName().orElse("anonymous");
+    log.atFine().log("operation %s unauthorized for user %s on project %s", op, userName, project);
     throw new LfsUnauthorized(op, project);
   }
 }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksContext.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksContext.java
index fa5f360..7ac56c7 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksContext.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksContext.java
@@ -20,6 +20,7 @@
 
 import com.google.common.base.Supplier;
 import com.google.common.base.Suppliers;
+import com.google.common.flogger.FluentLogger;
 import com.google.gson.FieldNamingPolicy;
 import com.google.gson.Gson;
 import com.google.gson.GsonBuilder;
@@ -32,11 +33,9 @@
 import java.io.Writer;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 class LfsLocksContext {
-  private static final Logger log = LoggerFactory.getLogger(LfsLocksContext.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
 
   public final String path;
 
@@ -101,7 +100,7 @@
   }
 
   void sendError(int status, Error error) throws IOException {
-    log.error(error.message);
+    log.atSevere().log(error.message);
     res.setStatus(status);
     gson.toJson(error, getWriter());
     getWriter().flush();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksHandler.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksHandler.java
index 3692374..1de28f4 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksHandler.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksHandler.java
@@ -17,6 +17,7 @@
 import com.google.common.cache.CacheLoader;
 import com.google.common.cache.LoadingCache;
 import com.google.common.collect.ImmutableList;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gerrit.server.cache.CacheModule;
@@ -30,8 +31,6 @@
 import java.util.Optional;
 import java.util.stream.Collectors;
 import org.eclipse.jgit.lfs.errors.LfsException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 @Singleton
 class LfsLocksHandler {
@@ -55,7 +54,7 @@
     }
   }
 
-  private static final Logger log = LoggerFactory.getLogger(LfsLocksHandler.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
   private static final String CACHE_NAME = "lfs_project_locks";
 
   static Module module() {
@@ -80,7 +79,7 @@
 
   LfsLockResponse createLock(Project.NameKey project, CurrentUser user, LfsCreateLockInput input)
       throws LfsException {
-    log.debug("Create lock for {} in project {}", input.path, project);
+    log.atFine().log("Create lock for %s in project %s", input.path, project);
     LfsProjectLocks locks = projectLocks.getUnchecked(project);
     LfsLock lock = locks.createLock(user, input);
     return new LfsLockResponse(lock);
@@ -89,11 +88,9 @@
   LfsLockResponse deleteLock(
       Project.NameKey project, CurrentUser user, String lockId, LfsDeleteLockInput input)
       throws LfsException {
-    log.debug(
-        "Delete (-f {}) lock for {} in project {}",
-        Boolean.TRUE.equals(input.force),
-        lockId,
-        project);
+    log.atFine().log(
+        "Delete (-f %s) lock for %s in project %s",
+        Boolean.TRUE.equals(input.force), lockId, project);
     LfsProjectLocks locks = projectLocks.getUnchecked(project);
     Optional<LfsLock> hasLock = locks.getLock(lockId);
     if (!hasLock.isPresent()) {
@@ -102,7 +99,7 @@
     }
 
     LfsLock lock = hasLock.get();
-    if (lock.owner.name.equals(user.getUserName())) {
+    if (lock.owner.name.equals(user.getUserName().get())) {
       locks.deleteLock(lock);
       return new LfsLockResponse(lock);
     } else if (input.force) {
@@ -115,26 +112,26 @@
   }
 
   LfsVerifyLocksResponse verifyLocks(Project.NameKey project, final CurrentUser user) {
-    log.debug("Verify list of locks for {} project and user {}", project, user);
+    log.atFine().log("Verify list of locks for %s project and user %s", project, user);
     LfsProjectLocks locks = projectLocks.getUnchecked(project);
     Map<Boolean, List<LfsLock>> groupByOurs =
         locks.getLocks().stream()
             .collect(
                 Collectors.groupingBy(
                     (in) -> {
-                      return in.owner.name.equals(user.getUserName());
+                      return in.owner.name.equals(user.getUserName().get());
                     }));
     return new LfsVerifyLocksResponse(groupByOurs.get(true), groupByOurs.get(false), null);
   }
 
   LfsGetLocksResponse listLocksByPath(Project.NameKey project, String path) {
-    log.debug("Get lock for {} path in {} project", path, project);
+    log.atFine().log("Get lock for %s path in %s project", path, project);
     String lockId = toLockId.apply(path);
     return listLocksById(project, lockId);
   }
 
   LfsGetLocksResponse listLocksById(Project.NameKey project, String id) {
-    log.debug("Get lock for {} id in {} project", id, project);
+    log.atFine().log("Get lock for %s id in %s project", id, project);
     LfsProjectLocks locks = projectLocks.getUnchecked(project);
     Optional<LfsLock> lock = locks.getLock(id);
     List<LfsLock> locksById =
@@ -143,7 +140,7 @@
   }
 
   LfsGetLocksResponse listLocks(Project.NameKey project) {
-    log.debug("Get locks for {} project", project);
+    log.atFine().log("Get locks for %s project", project);
     return new LfsGetLocksResponse(projectLocks.getUnchecked(project).getLocks(), null);
   }
 
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsProjectLocks.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsProjectLocks.java
index a578736..4276fba 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsProjectLocks.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsProjectLocks.java
@@ -16,6 +16,7 @@
 
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
+import com.google.common.flogger.FluentLogger;
 import com.google.gerrit.reviewdb.client.Project;
 import com.google.gerrit.server.CurrentUser;
 import com.google.gson.FieldNamingPolicy;
@@ -36,21 +37,18 @@
 import java.util.stream.Stream;
 import org.eclipse.jgit.internal.storage.file.LockFile;
 import org.eclipse.jgit.lfs.errors.LfsException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
 
 class LfsProjectLocks {
   interface Factory {
     LfsProjectLocks create(Project.NameKey project);
   }
 
-  private static final Logger log = LoggerFactory.getLogger(LfsProjectLocks.class);
+  private static final FluentLogger log = FluentLogger.forEnclosingClass();
   private static final Gson gson =
       new GsonBuilder()
           .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES)
           .disableHtmlEscaping()
           .create();
-
   private final PathToLockId toLockId;
   private final String project;
   private final Path locksPath;
@@ -75,7 +73,8 @@
           .forEach(
               path -> {
                 if (!Files.isReadable(path)) {
-                  log.warn("Lock file [{}] in project {} is not readable", path, project);
+                  log.atWarning().log(
+                      "Lock file [%s] in project %s is not readable", path, project);
                   return;
                 }
 
@@ -83,11 +82,11 @@
                   LfsLock lock = gson.fromJson(in, LfsLock.class);
                   locks.put(lock.id, lock);
                 } catch (IOException e) {
-                  log.warn("Reading lock [{}] failed", path, e);
+                  log.atWarning().withCause(e).log("Reading lock [%s] failed", path);
                 }
               });
     } catch (IOException e) {
-      log.warn("Reading locks in project {} failed", project, e);
+      log.atWarning().withCause(e).log("Reading locks in project %s failed", project);
     }
   }
 
@@ -96,18 +95,20 @@
   }
 
   LfsLock createLock(CurrentUser user, LfsCreateLockInput input) throws LfsException {
-    log.debug("Create lock for {} in project {}", input.path, project);
+    log.atFine().log("Create lock for %s in project %s", input.path, project);
     String lockId = toLockId.apply(input.path);
     LfsLock lock = locks.getIfPresent(lockId);
     if (lock != null) {
       throw new LfsLockExistsException(lock);
     }
 
-    lock = new LfsLock(lockId, input.path, LfsDateTime.now(), new LfsLockOwner(user.getUserName()));
+    lock =
+        new LfsLock(
+            lockId, input.path, LfsDateTime.now(), new LfsLockOwner(user.getUserName().get()));
     LockFile fileLock = new LockFile(locksPath.resolve(lockId).toFile());
     try {
       if (!fileLock.lock()) {
-        log.warn("Cannot lock path [{}] in project {}", input.path, project);
+        log.atWarning().log("Cannot lock path [%s] in project %s", input.path, project);
         throw new LfsLockExistsException(lock);
       }
     } catch (IOException e) {
@@ -115,7 +116,7 @@
           String.format(
               "Locking path [%s] in project %s failed with error %s",
               input.path, project, e.getMessage());
-      log.warn(error);
+      log.atWarning().log(error);
       throw new LfsException(error);
     }
 
@@ -127,13 +128,13 @@
             String.format(
                 "Locking path [%s] in project %s failed during write with error %s",
                 input.path, project, e.getMessage());
-        log.warn(error);
+        log.atWarning().log(error);
         throw new LfsException(error);
       }
       if (!fileLock.commit()) {
         String error =
             String.format("Committing lock to path [%s] in project %s failed", input.path, project);
-        log.warn(error);
+        log.atWarning().log(error);
         throw new LfsException(error);
       }
       // put lock object to cache while file lock is being hold so that
@@ -155,7 +156,7 @@
         String error =
             String.format(
                 "Deleting lock on path [%s] in project %s is not possible", lock.path, project);
-        log.warn(error);
+        log.atWarning().log(error);
         throw new LfsException(error);
       }
     } catch (IOException e) {
@@ -163,7 +164,7 @@
           String.format(
               "Getting lock on path [%s] in project %s failed with error %s",
               lock.path, project, e.getMessage());
-      log.warn(error);
+      log.atWarning().log(error);
       throw new LfsException(error);
     }
 
@@ -175,7 +176,7 @@
           String.format(
               "Deleting lock on path [%s] in project %s failed with error %s",
               lock.path, project, e.getMessage());
-      log.warn(error);
+      log.atWarning().log(error);
       throw new LfsException(error);
     } finally {
       fileLock.unlock();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsPutLocksAction.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsPutLocksAction.java
index ffbcc8d..39c7861 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsPutLocksAction.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsPutLocksAction.java
@@ -16,13 +16,16 @@
 
 import static com.google.gerrit.extensions.api.lfs.LfsDefinitions.LFS_URL_REGEX_TEMPLATE;
 import static com.google.gerrit.extensions.api.lfs.LfsDefinitions.LFS_VERIFICATION_PATH;
+import static com.google.gerrit.server.permissions.ProjectPermission.PUSH_AT_LEAST_ONE_REF;
 import static com.googlesource.gerrit.plugins.lfs.locks.LfsGetLocksAction.LFS_LOCKS_URL_PATTERN;
 
 import com.google.common.base.Strings;
-import com.google.gerrit.common.data.Capable;
+import com.google.gerrit.extensions.restapi.AuthException;
 import com.google.gerrit.server.CurrentUser;
+import com.google.gerrit.server.permissions.PermissionBackend;
+import com.google.gerrit.server.permissions.PermissionBackend.ForProject;
+import com.google.gerrit.server.permissions.PermissionBackendException;
 import com.google.gerrit.server.project.ProjectCache;
-import com.google.gerrit.server.project.ProjectControl;
 import com.google.gerrit.server.project.ProjectState;
 import com.google.inject.Inject;
 import com.google.inject.assistedinject.Assisted;
@@ -31,7 +34,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.eclipse.jgit.lfs.errors.LfsException;
-import org.eclipse.jgit.lfs.errors.LfsUnauthorized;
 
 public class LfsPutLocksAction extends LfsLocksAction {
   interface Factory extends LfsLocksAction.Factory<LfsPutLocksAction> {}
@@ -43,11 +45,12 @@
 
   @Inject
   LfsPutLocksAction(
+      PermissionBackend permissionBackend,
       ProjectCache projectCache,
       LfsAuthUserProvider userProvider,
       LfsLocksHandler handler,
       @Assisted LfsLocksContext context) {
-    super(projectCache, userProvider, handler, context);
+    super(permissionBackend, projectCache, userProvider, handler, context);
   }
 
   @Override
@@ -74,11 +77,15 @@
   }
 
   @Override
-  protected void authorizeUser(ProjectControl control) throws LfsUnauthorized {
+  protected void authorizeUser(ForProject project)
+      throws AuthException, PermissionBackendException {
     // all operations require push permission
-    if (Capable.OK != control.canPushToAtLeastOneRef()) {
-      throwUnauthorizedOp(action.getName(), control);
-    }
+    project.check(PUSH_AT_LEAST_ONE_REF);
+  }
+
+  @Override
+  protected String getAction() {
+    return action.getName();
   }
 
   @Override
diff --git a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java b/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java
index f41307b..5a72637 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java
@@ -30,9 +30,7 @@
     TestTokenProessor processor = new TestTokenProessor(cipher);
     TestToken token = new TestToken(Instant.now(), 0L);
     String serialized = processor.serialize(token);
-
     assertThat(serialized).isNotEmpty();
-
     Optional<TestToken> deserialized = processor.deserialize(serialized);
     assertThat(deserialized.isPresent()).isTrue();
     assertThat(token.issued).isEqualTo(deserialized.get().issued);