Introduce "git-lfs-authenticate" SSH Command for LFS plugins

According to [1] Git LFS can use SSH protocol to either obtain Git LFS
endpoint or authorize the following Git LFS request (upload/download).
This patchset introduces Git LFS SSH command stub that forwards call to
implementation provided by Git LFS plugin. In case no plugin is loaded
it exits with 1.

Different attempts to solve this problem were submitted for review ([2],
[3]) but there were either too generic or simply to controversial to
address the problem correctly. I believe that this attempt is superior
as:
1. it is specific to the problem - doesn't open any Pandora's box
2. it comes along with existing solution that adds Git LFS HTTP Servlet
endpoint that transfers Git LFS HTTP calls to plugin

[1]
https://github.com/git-lfs/git-lfs/blob/master/docs/api/server-discovery.md
[2] https://gerrit-review.googlesource.com/93496
[3] https://gerrit-review.googlesource.com/93373
Change-Id: I5f9b95c4b29cd8c0d64053e986851500f147eb5a
Signed-off-by: Jacek Centkowski <geminica.programs@gmail.com>
This commit is contained in:
Jacek Centkowski
2017-01-05 18:34:52 +01:00
parent 261ffcf84c
commit ae52c0450d
2 changed files with 69 additions and 0 deletions

View File

@@ -21,6 +21,7 @@ import com.google.gerrit.sshd.CommandName;
import com.google.gerrit.sshd.Commands;
import com.google.gerrit.sshd.DispatchCommandProvider;
import com.google.gerrit.sshd.SuExec;
import com.google.gerrit.sshd.plugin.LfsPluginAuthCommand;
/** Register the commands a Gerrit server supports. */
@@ -122,6 +123,8 @@ public class DefaultCommandModule extends CommandModule {
command(logging, ListLoggingLevelCommand.class);
alias(logging, "ls", ListLoggingLevelCommand.class);
alias(logging, "set", SetLoggingLevelCommand.class);
install(new LfsPluginAuthCommand.Module());
}
private boolean sshEnabled() {

View File

@@ -0,0 +1,66 @@
// Copyright (C) 2017 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.google.gerrit.sshd.plugin;
import com.google.gerrit.extensions.registration.DynamicItem;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.sshd.CommandModule;
import com.google.gerrit.sshd.SshCommand;
import com.google.inject.Inject;
import com.google.inject.Provider;
import org.kohsuke.args4j.Argument;
import java.util.ArrayList;
import java.util.List;
public class LfsPluginAuthCommand extends SshCommand {
public interface LfsSshPluginAuth {
String authenticate(CurrentUser user, List<String> args)
throws UnloggedFailure, Failure;
}
public static class Module extends CommandModule {
@Override
protected void configure() {
command("git-lfs-authenticate").to(LfsPluginAuthCommand.class);
DynamicItem.itemOf(binder(), LfsSshPluginAuth.class);
}
}
private final DynamicItem<LfsSshPluginAuth> auth;
private final Provider<CurrentUser> user;
@Argument(index = 0, multiValued = true, metaVar = "PARAMS")
private List<String> args = new ArrayList<>();
@Inject
LfsPluginAuthCommand(DynamicItem<LfsSshPluginAuth> auth,
Provider<CurrentUser> user) {
this.auth = auth;
this.user = user;
}
@Override
protected void run() throws UnloggedFailure, Failure, Exception {
LfsSshPluginAuth pluginAuth = auth.get();
if (pluginAuth == null) {
throw new Failure(1, "Server configuration error:"
+ " LFS auth over SSH is not properly configured.");
}
stdout.print(pluginAuth.authenticate(user.get(), args));
}
}