From 6cdb81d263fa77e2751312d3373efedd33c43cfb Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Fri, 18 Oct 2019 10:22:45 +0200 Subject: [PATCH] POC --- .../main/java/sonia/scm/LFSAuthCommand.java | 21 ++++++++++--- .../scm/web/lfs/ScmBlobLfsRepository.java | 31 ++++++++++++++++--- .../web/lfs/servlet/LfsServletFactory.java | 7 +++-- 3 files changed, 47 insertions(+), 12 deletions(-) diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/LFSAuthCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/LFSAuthCommand.java index 0864b84dfd..17a05ebe60 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/LFSAuthCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/LFSAuthCommand.java @@ -2,12 +2,14 @@ package sonia.scm; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; +import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; import sonia.scm.protocolcommand.CommandInterpreter; import sonia.scm.protocolcommand.CommandInterpreterFactory; -import sonia.scm.protocolcommand.RepositoryContext; import sonia.scm.protocolcommand.RepositoryContextResolver; import sonia.scm.protocolcommand.ScmCommandProtocol; +import sonia.scm.protocolcommand.git.GitRepositoryContextResolver; +import sonia.scm.repository.Repository; import sonia.scm.security.AccessToken; import sonia.scm.security.AccessTokenBuilderFactory; @@ -21,14 +23,20 @@ import java.util.Date; import java.util.Optional; import java.util.concurrent.TimeUnit; +import static java.lang.String.format; + @Extension public class LFSAuthCommand implements CommandInterpreterFactory { private final AccessTokenBuilderFactory tokenBuilderFactory; + private final GitRepositoryContextResolver gitRepositoryContextResolver; + private final ScmConfiguration configuration; @Inject - public LFSAuthCommand(AccessTokenBuilderFactory tokenBuilderFactory) { + public LFSAuthCommand(AccessTokenBuilderFactory tokenBuilderFactory, GitRepositoryContextResolver gitRepositoryContextResolver, ScmConfiguration configuration) { this.tokenBuilderFactory = tokenBuilderFactory; + this.gitRepositoryContextResolver = gitRepositoryContextResolver; + this.configuration = configuration; } @Override @@ -36,7 +44,7 @@ public class LFSAuthCommand implements CommandInterpreterFactory { return command.startsWith("git-lfs-authenticate") ? Optional.of(new CommandInterpreter() { @Override public String[] getParsedArgs() { - return new String[0]; + return new String[] {command.split("\\s+")[1]}; } @Override @@ -44,10 +52,13 @@ public class LFSAuthCommand implements CommandInterpreterFactory { return (context, repositoryContext) -> { AccessToken accessToken = tokenBuilderFactory.create().expiresIn(5, TimeUnit.MINUTES).build(); + Repository repository = repositoryContext.getRepository(); + String url = format("%s/repo/%s/%s.git/info/lfs/", configuration.getBaseUrl(), repository.getNamespace(), repository.getName()); + ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new JaxbAnnotationModule()); objectMapper.setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:MM:ss'Z'")); - LfsAuthResponse response = new LfsAuthResponse("http://localhost:8081/scm/repo/scmadmin/lfs.git/info/lfs/", new LfsAuthHeader(accessToken.compact()), Instant.now().plus(5, ChronoUnit.MINUTES)); + LfsAuthResponse response = new LfsAuthResponse(url, new LfsAuthHeader(accessToken.compact()), Instant.now().plus(5, ChronoUnit.MINUTES)); ByteArrayOutputStream buffer = new ByteArrayOutputStream(); objectMapper.writeValue(buffer, response); context.getOutputStream().write(buffer.toString().getBytes()); @@ -56,7 +67,7 @@ public class LFSAuthCommand implements CommandInterpreterFactory { @Override public RepositoryContextResolver getRepositoryContextResolver() { - return args -> new RepositoryContext(null, null); + return gitRepositoryContextResolver; } }) : Optional.empty(); } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/ScmBlobLfsRepository.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/ScmBlobLfsRepository.java index 46a58f6f07..06574ddd8d 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/ScmBlobLfsRepository.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/ScmBlobLfsRepository.java @@ -1,12 +1,21 @@ package sonia.scm.web.lfs; +import org.eclipse.jgit.lfs.Protocol; import org.eclipse.jgit.lfs.lib.AnyLongObjectId; import org.eclipse.jgit.lfs.server.LargeFileRepository; import org.eclipse.jgit.lfs.server.Response; +import sonia.scm.security.AccessToken; +import sonia.scm.security.AccessTokenBuilderFactory; import sonia.scm.store.Blob; import sonia.scm.store.BlobStore; import java.io.IOException; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.HashMap; +import java.util.concurrent.TimeUnit; /** * This LargeFileRepository is used for jGit-Servlet implementation. Under the jgit LFS Servlet hood, the @@ -18,6 +27,7 @@ import java.io.IOException; public class ScmBlobLfsRepository implements LargeFileRepository { private final BlobStore blobStore; + private final AccessTokenBuilderFactory tokenBuilderFactory; /** * This URI is used to determine the actual URI for Upload / Download. Must be full URI (or rewritable by reverse @@ -28,14 +38,15 @@ public class ScmBlobLfsRepository implements LargeFileRepository { /** * Creates a {@link ScmBlobLfsRepository} for the provided repository. * - * @param blobStore The SCM Blobstore used for this @{@link LargeFileRepository}. - * @param baseUri This URI is used to determine the actual URI for Upload / Download. Must be full URI (or - * rewritable by reverse proxy). + * @param blobStore The SCM Blobstore used for this @{@link LargeFileRepository}. + * @param tokenBuilderFactory + * @param baseUri This URI is used to determine the actual URI for Upload / Download. Must be full URI (or */ - public ScmBlobLfsRepository(BlobStore blobStore, String baseUri) { + public ScmBlobLfsRepository(BlobStore blobStore, AccessTokenBuilderFactory tokenBuilderFactory, String baseUri) { this.blobStore = blobStore; + this.tokenBuilderFactory = tokenBuilderFactory; this.baseUri = baseUri; } @@ -82,9 +93,19 @@ public class ScmBlobLfsRepository implements LargeFileRepository { //LFS protocol has to provide the information on where to put or get the actual content, i. e. //the actual URI for up- and download. - Response.Action a = new Response.Action(); + ExpiringAction a = new ExpiringAction(); a.href = baseUri + id.getName(); + AccessToken accessToken = tokenBuilderFactory.create().expiresIn(5, TimeUnit.MINUTES).build(); + a.header = new HashMap<>(); + a.header.put("Authorization", "Bearer " + accessToken.compact()); + Instant expire = Instant.now().plus(5, ChronoUnit.MINUTES); + a.expires_at = new SimpleDateFormat("yyyy-MM-dd'T'HH:MM:ss'Z'").format(Date.from(expire)); + return a; } + + private static class ExpiringAction extends Response.Action { + public String expires_at; + } } diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/servlet/LfsServletFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/servlet/LfsServletFactory.java index f4eed34678..f174f6e8aa 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/servlet/LfsServletFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/servlet/LfsServletFactory.java @@ -7,6 +7,7 @@ import org.eclipse.jgit.lfs.server.fs.FileLfsServlet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import sonia.scm.repository.Repository; +import sonia.scm.security.AccessTokenBuilderFactory; import sonia.scm.store.BlobStore; import sonia.scm.util.HttpUtil; import sonia.scm.web.lfs.LfsBlobStoreFactory; @@ -30,10 +31,12 @@ public class LfsServletFactory { private static final Logger logger = LoggerFactory.getLogger(LfsServletFactory.class); private final LfsBlobStoreFactory lfsBlobStoreFactory; + private final AccessTokenBuilderFactory tokenBuilderFactory; @Inject - public LfsServletFactory(LfsBlobStoreFactory lfsBlobStoreFactory) { + public LfsServletFactory(LfsBlobStoreFactory lfsBlobStoreFactory, AccessTokenBuilderFactory tokenBuilderFactory) { this.lfsBlobStoreFactory = lfsBlobStoreFactory; + this.tokenBuilderFactory = tokenBuilderFactory; } /** @@ -47,7 +50,7 @@ public class LfsServletFactory { BlobStore blobStore = lfsBlobStoreFactory.getLfsBlobStore(repository); String baseUri = buildBaseUri(repository, request); - LargeFileRepository largeFileRepository = new ScmBlobLfsRepository(blobStore, baseUri); + LargeFileRepository largeFileRepository = new ScmBlobLfsRepository(blobStore, tokenBuilderFactory, baseUri); return new ScmLfsProtocolServlet(largeFileRepository); }