Merge branch 'stable-2.15' into stable-2.16 * stable-2.15: Make transitive starlark loads explicit Make transitive starlark loads explicit Change-Id: I3aa5de554b7a7832397740769383aa5ed2a5fc6a
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 7b73315..43bcefc 100644 --- a/WORKSPACE +++ b/WORKSPACE
@@ -3,7 +3,7 @@ load("//:bazlets.bzl", "load_bazlets") load_bazlets( - commit = "70d6ae0cee03c456fa4b32c807f3d13c032ef498", + commit = "d100b6aad6b37e7db8fa141020c882dc97fb7723", #local_path = "/home/<user>/projects/bazlets", )
diff --git a/external_plugin_deps.bzl b/external_plugin_deps.bzl index 0882ce4..a5277e6 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.10.201904181027-r" +JGIT_VERSION = "5.1.7.201904200442-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 = "4f9bdd283d14b366ab13842d9703631d1fdf7e77", + sha1 = "3255f0c211deced0c13fbbfca8bf9f8dd58b69b1", 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 = "f7821575a2b6c2173fb230cd1b54e911e5d44448", + sha1 = "32a44fd5cbe1da07297e60aaeafce3d220b2fc1b", 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 = "968be15ac26f7929470fecc48086ef64ed2838af", + sha1 = "b79632ce4c376edd4517410d49ada5ac0b5c4649", 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/GetLfsGlobalConfig.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/GetLfsGlobalConfig.java index 40e00b0..ebbc81c 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/GetLfsGlobalConfig.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/GetLfsGlobalConfig.java
@@ -14,19 +14,11 @@ package com.googlesource.gerrit.plugins.lfs; -import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER; - import com.google.common.collect.Maps; -import com.google.gerrit.extensions.restapi.ResourceNotFoundException; import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestReadView; -import com.google.gerrit.server.CurrentUser; -import com.google.gerrit.server.IdentifiedUser; -import com.google.gerrit.server.config.AllProjectsName; -import com.google.gerrit.server.permissions.PermissionBackend; import com.google.gerrit.server.project.ProjectResource; import com.google.inject.Inject; -import com.google.inject.Provider; import com.google.inject.Singleton; import java.util.HashMap; import java.util.List; @@ -34,29 +26,17 @@ @Singleton class GetLfsGlobalConfig implements RestReadView<ProjectResource> { private final LfsConfigurationFactory lfsConfigFactory; - private final AllProjectsName allProjectsName; - private final Provider<CurrentUser> self; - private final PermissionBackend permissionBackend; + private final LfsAdminView adminView; @Inject - GetLfsGlobalConfig( - LfsConfigurationFactory lfsConfigFactory, - AllProjectsName allProjectsName, - Provider<CurrentUser> self, - PermissionBackend permissionBackend) { + GetLfsGlobalConfig(LfsConfigurationFactory lfsConfigFactory, LfsAdminView adminView) { this.lfsConfigFactory = lfsConfigFactory; - this.allProjectsName = allProjectsName; - this.self = self; - this.permissionBackend = permissionBackend; + this.adminView = adminView; } @Override public LfsGlobalConfigInfo apply(ProjectResource resource) throws RestApiException { - IdentifiedUser user = self.get().asIdentifiedUser(); - if (!(resource.getNameKey().equals(allProjectsName) - && permissionBackend.user(user).testOrFalse(ADMINISTRATE_SERVER))) { - throw new ResourceNotFoundException(); - } + adminView.validate(resource); LfsGlobalConfigInfo info = new LfsGlobalConfigInfo(); LfsGlobalConfig globalConfig = lfsConfigFactory.getGlobalConfig();
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAdminView.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAdminView.java new file mode 100644 index 0000000..d9d2ad7 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAdminView.java
@@ -0,0 +1,57 @@ +// Copyright (C) 2019 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.lfs; + +import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER; + +import com.google.gerrit.extensions.restapi.ResourceNotFoundException; +import com.google.gerrit.server.CurrentUser; +import com.google.gerrit.server.config.AllProjectsName; +import com.google.gerrit.server.permissions.PermissionBackend; +import com.google.gerrit.server.project.ProjectResource; +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.google.inject.Singleton; + +@Singleton +public class LfsAdminView { + private final AllProjectsName allProjectsName; + private final PermissionBackend permissionBackend; + private final Provider<CurrentUser> self; + + @Inject + LfsAdminView( + AllProjectsName allProjectsName, + PermissionBackend permissionBackend, + Provider<CurrentUser> self) { + this.allProjectsName = allProjectsName; + this.permissionBackend = permissionBackend; + this.self = self; + } + + /** + * Validate REST call. + * + * @param resource the resource + * @throws ResourceNotFoundException if the calling user is not admin, or the resource is not + * {@code All-Projects}. + */ + public void validate(ProjectResource resource) throws ResourceNotFoundException { + if (!(resource.getNameKey().equals(allProjectsName) + && permissionBackend.user(self.get()).testOrFalse(ADMINISTRATE_SERVER))) { + throw new ResourceNotFoundException(); + } + } +}
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..8982dbe 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsApiServlet.java
@@ -19,18 +19,18 @@ 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; +import com.googlesource.gerrit.plugins.lfs.auth.LfsAuthUserProvider; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.jgit.lfs.errors.LfsException; @@ -42,15 +42,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 +123,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/LfsGson.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsGson.java new file mode 100644 index 0000000..66398fe --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsGson.java
@@ -0,0 +1,49 @@ +// Copyright (C) 2019 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.lfs; + +import com.google.gson.FieldNamingPolicy; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonIOException; +import com.google.gson.JsonSyntaxException; +import com.google.inject.Singleton; +import java.io.Reader; + +@Singleton +public class LfsGson { + private final Gson gson; + + LfsGson() { + this.gson = + new GsonBuilder() + .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) + .disableHtmlEscaping() + .create(); + } + + public void toJson(Object src, Appendable writer) throws JsonIOException { + gson.toJson(src, writer); + } + + public String toJson(Object src) { + return gson.toJson(src); + } + + public <T> T fromJson(Reader json, Class<T> classOfT) + throws JsonSyntaxException, JsonIOException { + return gson.fromJson(json, classOfT); + } +}
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/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 b747925..ea4e44e 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/PutLfsGlobalConfig.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/PutLfsGlobalConfig.java
@@ -14,7 +14,6 @@ package com.googlesource.gerrit.plugins.lfs; -import static com.google.gerrit.server.permissions.GlobalPermission.ADMINISTRATE_SERVER; import static com.googlesource.gerrit.plugins.lfs.LfsProjectConfigSection.KEY_BACKEND; import static com.googlesource.gerrit.plugins.lfs.LfsProjectConfigSection.KEY_ENABLED; import static com.googlesource.gerrit.plugins.lfs.LfsProjectConfigSection.KEY_MAX_OBJECT_SIZE; @@ -27,11 +26,7 @@ import com.google.gerrit.extensions.restapi.RestApiException; import com.google.gerrit.extensions.restapi.RestModifyView; import com.google.gerrit.reviewdb.client.Project; -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.permissions.PermissionBackend; +import com.google.gerrit.server.git.meta.MetaDataUpdate; import com.google.gerrit.server.project.ProjectResource; import com.google.inject.Inject; import com.google.inject.Provider; @@ -48,9 +43,7 @@ class PutLfsGlobalConfig implements RestModifyView<ProjectResource, LfsGlobalConfigInput> { private final String pluginName; - private final AllProjectsName allProjectsName; - private final PermissionBackend permissionBackend; - private final Provider<CurrentUser> self; + private final LfsAdminView adminView; private final Provider<MetaDataUpdate.User> metaDataUpdateFactory; private final LfsConfigurationFactory lfsConfigFactory; private final GetLfsGlobalConfig get; @@ -58,16 +51,12 @@ @Inject PutLfsGlobalConfig( @PluginName String pluginName, - AllProjectsName allProjectsName, - PermissionBackend permissionBackend, - Provider<CurrentUser> self, + LfsAdminView adminView, Provider<MetaDataUpdate.User> metaDataUpdateFactory, LfsConfigurationFactory lfsConfigFactory, GetLfsGlobalConfig get) { this.pluginName = pluginName; - this.allProjectsName = allProjectsName; - this.permissionBackend = permissionBackend; - this.self = self; + this.adminView = adminView; this.metaDataUpdateFactory = metaDataUpdateFactory; this.lfsConfigFactory = lfsConfigFactory; this.get = get; @@ -76,14 +65,9 @@ @Override public LfsGlobalConfigInfo apply(ProjectResource resource, LfsGlobalConfigInput input) throws RestApiException { - IdentifiedUser user = self.get().asIdentifiedUser(); + adminView.validate(resource); Project.NameKey projectName = resource.getNameKey(); - if (!(projectName.equals(allProjectsName) - && permissionBackend.user(user).testOrFalse(ADMINISTRATE_SERVER))) { - throw new ResourceNotFoundException(); - } - if (input == null) { input = new LfsGlobalConfigInput(); }
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/SshModule.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/SshModule.java index e74e813..931ffce 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/SshModule.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/SshModule.java
@@ -17,6 +17,7 @@ import com.google.gerrit.extensions.registration.DynamicItem; import com.google.gerrit.sshd.PluginCommandModule; import com.google.gerrit.sshd.plugin.LfsPluginAuthCommand; +import com.googlesource.gerrit.plugins.lfs.auth.LfsSshAuth; public class SshModule extends PluginCommandModule {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/AuthInfo.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/AuthInfo.java similarity index 93% rename from src/main/java/com/googlesource/gerrit/plugins/lfs/AuthInfo.java rename to src/main/java/com/googlesource/gerrit/plugins/lfs/auth/AuthInfo.java index 4336ed5..9b765d2 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/AuthInfo.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/AuthInfo.java
@@ -12,8 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; +import com.googlesource.gerrit.plugins.lfs.LfsDateTime; import java.time.Instant; public class AuthInfo {
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/ExpiringAction.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/ExpiringAction.java similarity index 95% rename from src/main/java/com/googlesource/gerrit/plugins/lfs/ExpiringAction.java rename to src/main/java/com/googlesource/gerrit/plugins/lfs/auth/ExpiringAction.java index d3255a1..133a386 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/ExpiringAction.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/ExpiringAction.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; import static org.eclipse.jgit.util.HttpSupport.HDR_AUTHORIZATION;
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsAuthToken.java similarity index 97% rename from src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java rename to src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsAuthToken.java index 909d295..7abce2c 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthToken.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsAuthToken.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; import com.google.common.base.Joiner; import com.google.common.base.Splitter; @@ -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/auth/LfsAuthUserProvider.java similarity index 87% rename from src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthUserProvider.java rename to src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsAuthUserProvider.java index f7d3078..fcd4736 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsAuthUserProvider.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsAuthUserProvider.java
@@ -12,9 +12,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; -import static com.googlesource.gerrit.plugins.lfs.LfsSshRequestAuthorizer.SSH_AUTH_PREFIX; +import static com.googlesource.gerrit.plugins.lfs.auth.LfsSshRequestAuthorizer.SSH_AUTH_PREFIX; import com.google.common.base.Strings; import com.google.gerrit.server.AnonymousUser; @@ -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/auth/LfsCipher.java similarity index 88% rename from src/main/java/com/googlesource/gerrit/plugins/lfs/LfsCipher.java rename to src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsCipher.java index aec332a..710b3c1 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsCipher.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsCipher.java
@@ -12,11 +12,12 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; 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/LfsSshAuth.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsSshAuth.java similarity index 84% rename from src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshAuth.java rename to src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsSshAuth.java index 08d7ca7..9fd57b9 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshAuth.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsSshAuth.java
@@ -12,19 +12,17 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; import com.google.gerrit.server.CurrentUser; import com.google.gerrit.server.config.CanonicalWebUrl; import com.google.gerrit.sshd.BaseCommand.Failure; import com.google.gerrit.sshd.BaseCommand.UnloggedFailure; import com.google.gerrit.sshd.plugin.LfsPluginAuthCommand; -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.inject.Inject; import com.google.inject.Provider; import com.google.inject.Singleton; +import com.googlesource.gerrit.plugins.lfs.LfsGson; import java.net.MalformedURLException; import java.net.URL; import java.util.List; @@ -33,17 +31,16 @@ public class LfsSshAuth implements LfsPluginAuthCommand.LfsSshPluginAuth { private final LfsSshRequestAuthorizer auth; private final String canonicalWebUrl; - private final Gson gson; + private final LfsGson gson; @Inject - LfsSshAuth(LfsSshRequestAuthorizer auth, @CanonicalWebUrl Provider<String> canonicalWebUrl) { + LfsSshAuth( + LfsSshRequestAuthorizer auth, + @CanonicalWebUrl Provider<String> canonicalWebUrl, + LfsGson gson) { this.auth = auth; this.canonicalWebUrl = canonicalWebUrl.get(); - this.gson = - new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .disableHtmlEscaping() - .create(); + this.gson = gson; } @Override
diff --git a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsSshRequestAuthorizer.java similarity index 86% rename from src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java rename to src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsSshRequestAuthorizer.java index 12c5552..14803ed 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/LfsSshRequestAuthorizer.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/auth/LfsSshRequestAuthorizer.java
@@ -12,17 +12,18 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; +import com.google.common.flogger.FluentLogger; import com.google.gerrit.server.CurrentUser; import com.google.inject.Inject; import com.google.inject.Singleton; +import com.googlesource.gerrit.plugins.lfs.LfsConfigurationFactory; +import com.googlesource.gerrit.plugins.lfs.LfsDateTime; import java.time.Instant; 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 +33,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 +49,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 +67,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 +97,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/fs/LfsFsDataDirectoryManager.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsDataDirectoryManager.java new file mode 100644 index 0000000..d8e6366 --- /dev/null +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsDataDirectoryManager.java
@@ -0,0 +1,68 @@ +// Copyright (C) 2019 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.lfs.fs; + +import com.google.common.base.Strings; +import com.google.gerrit.extensions.annotations.PluginData; +import com.google.inject.Inject; +import com.google.inject.Singleton; +import com.googlesource.gerrit.plugins.lfs.LfsBackend; +import com.googlesource.gerrit.plugins.lfs.LfsConfigurationFactory; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +@Singleton +public class LfsFsDataDirectoryManager { + private static final String KEY_DIRECTORY = "directory"; + + private final LfsConfigurationFactory configFactory; + private final Path defaultDataDir; + + @Inject + LfsFsDataDirectoryManager( + LfsConfigurationFactory configFactory, @PluginData Path defaultDataDir) { + this.configFactory = configFactory; + this.defaultDataDir = defaultDataDir; + } + + public Path ensureForBackend(LfsBackend backend) throws IOException { + return getForBackend(backend, true); + } + + public Path getForBackend(LfsBackend backend, boolean ensure) throws IOException { + String dataDir = + configFactory.getGlobalConfig().getString(backend.type.name(), backend.name, KEY_DIRECTORY); + if (Strings.isNullOrEmpty(dataDir)) { + return defaultDataDir; + } + + if (ensure) { + // note that the following method not only creates missing + // directory/directories but throws exception when path + // exists and points to file + Path ensured = Files.createDirectories(Paths.get(dataDir)); + + // we should at least make sure that directory is readable + if (!Files.isReadable(ensured)) { + throw new IOException("Path '" + ensured.toAbsolutePath() + "' cannot be accessed"); + } + + return ensured; + } + return Paths.get(dataDir); + } +}
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..279217b 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
@@ -16,10 +16,10 @@ import com.google.inject.Inject; import com.google.inject.Singleton; -import com.googlesource.gerrit.plugins.lfs.AuthInfo; -import com.googlesource.gerrit.plugins.lfs.LfsAuthToken; -import com.googlesource.gerrit.plugins.lfs.LfsCipher; import com.googlesource.gerrit.plugins.lfs.LfsDateTime; +import com.googlesource.gerrit.plugins.lfs.auth.AuthInfo; +import com.googlesource.gerrit.plugins.lfs.auth.LfsAuthToken; +import com.googlesource.gerrit.plugins.lfs.auth.LfsCipher; import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -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/fs/LocalLargeFileRepository.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LocalLargeFileRepository.java index 0a6ef34..069d163 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LocalLargeFileRepository.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/fs/LocalLargeFileRepository.java
@@ -17,20 +17,14 @@ import static org.eclipse.jgit.lfs.lib.Constants.DOWNLOAD; import static org.eclipse.jgit.lfs.lib.Constants.UPLOAD; -import com.google.common.base.Strings; import com.google.gerrit.extensions.annotations.PluginCanonicalWebUrl; -import com.google.gerrit.extensions.annotations.PluginData; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; -import com.googlesource.gerrit.plugins.lfs.AuthInfo; -import com.googlesource.gerrit.plugins.lfs.ExpiringAction; import com.googlesource.gerrit.plugins.lfs.LfsBackend; import com.googlesource.gerrit.plugins.lfs.LfsConfigurationFactory; -import com.googlesource.gerrit.plugins.lfs.LfsGlobalConfig; +import com.googlesource.gerrit.plugins.lfs.auth.AuthInfo; +import com.googlesource.gerrit.plugins.lfs.auth.ExpiringAction; import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; import java.time.Instant; import org.eclipse.jgit.lfs.lib.AnyLongObjectId; import org.eclipse.jgit.lfs.server.Response; @@ -50,15 +44,13 @@ @Inject LocalLargeFileRepository( + LfsFsDataDirectoryManager dataDirManager, LfsConfigurationFactory configFactory, LfsFsRequestAuthorizer authorizer, @PluginCanonicalWebUrl String url, - @PluginData Path defaultDataDir, @Assisted LfsBackend backend) throws IOException { - super( - getContentUrl(url, backend), - getOrCreateDataDir(configFactory.getGlobalConfig(), backend, defaultDataDir)); + super(getContentUrl(url, backend), dataDirManager.ensureForBackend(backend)); this.authorizer = authorizer; this.servletUrlPattern = "/" + getContentPath(backend) + "*"; this.expiresIn = @@ -99,24 +91,4 @@ private static String getContentPath(LfsBackend backend) { return String.format(CONTENT_PATH_TEMPLATE, backend.name()); } - - private static Path getOrCreateDataDir( - LfsGlobalConfig config, LfsBackend backendConfig, Path defaultDataDir) throws IOException { - String dataDir = config.getString(backendConfig.type.name(), backendConfig.name, "directory"); - if (Strings.isNullOrEmpty(dataDir)) { - return defaultDataDir; - } - - // note that the following method not only creates missing - // directory/directories but throws exception when path - // exists and points to file - Path ensured = Files.createDirectories(Paths.get(dataDir)); - - // we should at least make sure that directory is readable - if (!Files.isReadable(ensured)) { - throw new IOException("Path '" + ensured.toAbsolutePath() + "' cannot be accessed"); - } - - return ensured; - } }
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..a84d458 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,18 +23,17 @@ 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; -import com.googlesource.gerrit.plugins.lfs.LfsAuthUserProvider; +import com.googlesource.gerrit.plugins.lfs.auth.LfsAuthUserProvider; import java.io.IOException; 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..4b6afb4 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,28 +21,29 @@ 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.auth.LfsAuthUserProvider; import com.googlesource.gerrit.plugins.lfs.locks.LfsLocksHandler.LfsLockExistsException; import java.io.IOException; 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..5e4094c 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,9 +20,8 @@ import com.google.common.base.Supplier; import com.google.common.base.Suppliers; -import com.google.gson.FieldNamingPolicy; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; +import com.google.common.flogger.FluentLogger; +import com.googlesource.gerrit.plugins.lfs.LfsGson; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.IOException; @@ -32,11 +31,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; @@ -44,9 +41,9 @@ private final HttpServletResponse res; private final Supplier<Writer> writer; private final Supplier<Reader> reader; - private final Gson gson; + private final LfsGson gson; - LfsLocksContext(final HttpServletRequest req, final HttpServletResponse res) { + LfsLocksContext(LfsGson gson, final HttpServletRequest req, final HttpServletResponse res) { this.path = req.getPathInfo().startsWith("/") ? req.getPathInfo() : "/" + req.getPathInfo(); this.req = req; this.res = res; @@ -74,7 +71,7 @@ } } }); - this.gson = createGson(); + this.gson = gson; setLfsResponseType(); } @@ -101,7 +98,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(); @@ -119,13 +116,6 @@ res.setContentType(CONTENTTYPE_VND_GIT_LFS_JSON); } - private Gson createGson() { - return new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .disableHtmlEscaping() - .create(); - } - /** copied from org.eclipse.jgit.lfs.server.LfsProtocolServlet.Error */ static class Error { String message;
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/LfsLocksServlet.java b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksServlet.java index 9cdeb62..1e6146d 100644 --- a/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksServlet.java +++ b/src/main/java/com/googlesource/gerrit/plugins/lfs/locks/LfsLocksServlet.java
@@ -20,6 +20,7 @@ import com.google.inject.Inject; import com.google.inject.Singleton; +import com.googlesource.gerrit.plugins.lfs.LfsGson; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -35,24 +36,27 @@ private final LfsGetLocksAction.Factory getters; private final LfsPutLocksAction.Factory putters; + private final LfsGson gson; @Inject - LfsLocksServlet(LfsGetLocksAction.Factory getters, LfsPutLocksAction.Factory putters) { + LfsLocksServlet( + LfsGetLocksAction.Factory getters, LfsPutLocksAction.Factory putters, LfsGson gson) { this.getters = getters; this.putters = putters; + this.gson = gson; } @Override protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - LfsLocksContext context = new LfsLocksContext(req, resp); + LfsLocksContext context = new LfsLocksContext(gson, req, resp); getters.create(context).run(); } @Override protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException { - LfsLocksContext context = new LfsLocksContext(req, resp); + LfsLocksContext context = new LfsLocksContext(gson, req, resp); putters.create(context).run(); } }
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..4526fa4 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,14 +16,13 @@ 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; -import com.google.gson.Gson; -import com.google.gson.GsonBuilder; import com.google.inject.Inject; import com.google.inject.assistedinject.Assisted; import com.googlesource.gerrit.plugins.lfs.LfsDateTime; +import com.googlesource.gerrit.plugins.lfs.LfsGson; import com.googlesource.gerrit.plugins.lfs.locks.LfsLocksHandler.LfsLockExistsException; import java.io.IOException; import java.io.OutputStreamWriter; @@ -36,21 +35,14 @@ 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 Gson gson = - new GsonBuilder() - .setFieldNamingPolicy(FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES) - .disableHtmlEscaping() - .create(); - + private static final FluentLogger log = FluentLogger.forEnclosingClass(); + private final LfsGson gson; private final PathToLockId toLockId; private final String project; private final Path locksPath; @@ -58,7 +50,11 @@ @Inject LfsProjectLocks( - PathToLockId toLockId, LfsLocksPathProvider locksPath, @Assisted Project.NameKey project) { + LfsGson gson, + PathToLockId toLockId, + LfsLocksPathProvider locksPath, + @Assisted Project.NameKey project) { + this.gson = gson; this.toLockId = toLockId; this.project = project.get(); this.locksPath = Paths.get(locksPath.get(), this.project); @@ -75,7 +71,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 +80,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 +93,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 +114,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 +126,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 +154,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 +162,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 +174,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..9e0e23d 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,22 +16,24 @@ 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; -import com.googlesource.gerrit.plugins.lfs.LfsAuthUserProvider; +import com.googlesource.gerrit.plugins.lfs.auth.LfsAuthUserProvider; import java.io.IOException; 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/LfsIT.java b/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsIT.java new file mode 100644 index 0000000..c71a83c --- /dev/null +++ b/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsIT.java
@@ -0,0 +1,55 @@ +// Copyright (C) 2019 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.lfs; + +import com.google.gerrit.acceptance.LightweightPluginDaemonTest; +import com.google.gerrit.acceptance.TestPlugin; +import com.google.gerrit.reviewdb.client.Project; +import com.google.gerrit.testing.ConfigSuite; +import org.eclipse.jgit.lib.Config; +import org.junit.Test; + +@TestPlugin( + name = "lfs", + sysModule = "com.googlesource.gerrit.plugins.lfs.Module", + httpModule = "com.googlesource.gerrit.plugins.lfs.HttpModule", + sshModule = "com.googlesource.gerrit.plugins.lfs.SshModule") +public class LfsIT extends LightweightPluginDaemonTest { + @ConfigSuite.Default + public static Config enablePlugin() { + Config cfg = new Config(); + cfg.setString("lfs", null, "plugin", "lfs"); + return cfg; + } + + @Test + public void globalConfigCanBeReadByAdmin() throws Exception { + adminRestSession.get(globalConfig(allProjects)).assertOK(); + } + + @Test + public void globalConfigCannotBeReadByNonAdmin() throws Exception { + userRestSession.get(globalConfig(allProjects)).assertNotFound(); + } + + @Test + public void globalConfigCannotBeReadOnOtherProject() throws Exception { + adminRestSession.get(globalConfig(project)).assertNotFound(); + } + + private static String globalConfig(Project.NameKey name) { + return String.format("/projects/%s/lfs:config-global", name.get()); + } +}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java b/src/test/java/com/googlesource/gerrit/plugins/lfs/auth/LfsAuthTokenTest.java similarity index 96% rename from src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java rename to src/test/java/com/googlesource/gerrit/plugins/lfs/auth/LfsAuthTokenTest.java index f41307b..bdf7c21 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsAuthTokenTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/lfs/auth/LfsAuthTokenTest.java
@@ -12,10 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; import static com.google.common.truth.Truth.assertThat; +import com.googlesource.gerrit.plugins.lfs.LfsDateTime; import java.time.Instant; import java.util.ArrayList; import java.util.List; @@ -30,9 +31,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);
diff --git a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsCipherTest.java b/src/test/java/com/googlesource/gerrit/plugins/lfs/auth/LfsCipherTest.java similarity index 97% rename from src/test/java/com/googlesource/gerrit/plugins/lfs/LfsCipherTest.java rename to src/test/java/com/googlesource/gerrit/plugins/lfs/auth/LfsCipherTest.java index b092a48..08d8dc8 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/lfs/LfsCipherTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/lfs/auth/LfsCipherTest.java
@@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package com.googlesource.gerrit.plugins.lfs; +package com.googlesource.gerrit.plugins.lfs.auth; import static com.google.common.truth.Truth.assertThat;
diff --git a/src/test/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizerTest.java b/src/test/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizerTest.java index 8cd7225..d2b38c2 100644 --- a/src/test/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizerTest.java +++ b/src/test/java/com/googlesource/gerrit/plugins/lfs/fs/LfsFsRequestAuthorizerTest.java
@@ -17,8 +17,8 @@ import static com.google.common.truth.Truth.assertThat; import static org.eclipse.jgit.lfs.lib.LongObjectId.zeroId; -import com.googlesource.gerrit.plugins.lfs.AuthInfo; -import com.googlesource.gerrit.plugins.lfs.LfsCipher; +import com.googlesource.gerrit.plugins.lfs.auth.AuthInfo; +import com.googlesource.gerrit.plugins.lfs.auth.LfsCipher; import com.googlesource.gerrit.plugins.lfs.fs.LfsFsRequestAuthorizer.Processor; import java.time.Instant; import org.eclipse.jgit.lfs.lib.LongObjectId;