From 9f48875d57e72d2c1fc94eb4aa536c1b0bc2e6f4 Mon Sep 17 00:00:00 2001 From: Rene Pfeuffer Date: Thu, 17 Oct 2019 09:23:37 +0200 Subject: [PATCH] POC --- scm-plugins/scm-git-plugin/pom.xml | 6 ++ .../main/java/sonia/scm/LFSAuthCommand.java | 101 ++++++++++++++++++ 2 files changed, 107 insertions(+) create mode 100644 scm-plugins/scm-git-plugin/src/main/java/sonia/scm/LFSAuthCommand.java diff --git a/scm-plugins/scm-git-plugin/pom.xml b/scm-plugins/scm-git-plugin/pom.xml index 0456370c99..0cace5e94d 100644 --- a/scm-plugins/scm-git-plugin/pom.xml +++ b/scm-plugins/scm-git-plugin/pom.xml @@ -40,6 +40,12 @@ 2.6 + + org.jboss.resteasy + resteasy-jackson2-provider + ${resteasy.version} + + 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 new file mode 100644 index 0000000000..0864b84dfd --- /dev/null +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/LFSAuthCommand.java @@ -0,0 +1,101 @@ +package sonia.scm; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule; +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.security.AccessToken; +import sonia.scm.security.AccessTokenBuilderFactory; + +import javax.inject.Inject; +import javax.xml.bind.annotation.XmlElement; +import java.io.ByteArrayOutputStream; +import java.text.SimpleDateFormat; +import java.time.Instant; +import java.time.temporal.ChronoUnit; +import java.util.Date; +import java.util.Optional; +import java.util.concurrent.TimeUnit; + +@Extension +public class LFSAuthCommand implements CommandInterpreterFactory { + + private final AccessTokenBuilderFactory tokenBuilderFactory; + + @Inject + public LFSAuthCommand(AccessTokenBuilderFactory tokenBuilderFactory) { + this.tokenBuilderFactory = tokenBuilderFactory; + } + + @Override + public Optional canHandle(String command) { + return command.startsWith("git-lfs-authenticate") ? Optional.of(new CommandInterpreter() { + @Override + public String[] getParsedArgs() { + return new String[0]; + } + + @Override + public ScmCommandProtocol getProtocolHandler() { + return (context, repositoryContext) -> { + AccessToken accessToken = tokenBuilderFactory.create().expiresIn(5, TimeUnit.MINUTES).build(); + + 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)); + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + objectMapper.writeValue(buffer, response); + context.getOutputStream().write(buffer.toString().getBytes()); + }; + } + + @Override + public RepositoryContextResolver getRepositoryContextResolver() { + return args -> new RepositoryContext(null, null); + } + }) : Optional.empty(); + } + + private class LfsAuthResponse { + private final String href; + private final LfsAuthHeader header; + @XmlElement(name = "expires_at") + private final Date expiresAt; + + public LfsAuthResponse(String href, LfsAuthHeader header, Instant expiresAt) { + this.href = href; + this.header = header; + this.expiresAt = Date.from(expiresAt); + } + + public String getHref() { + return href; + } + + public LfsAuthHeader getHeader() { + return header; + } + + public Date getExpiresAt() { + return expiresAt; + } + } + + private class LfsAuthHeader { + @XmlElement(name = "Authorization") + private final String authorization; + + public LfsAuthHeader(String authorization) { + this.authorization = authorization; + } + + public String getAuthorization() { + return "Bearer " + authorization; + } + } +}