Extract common functionality

This commit is contained in:
Rene Pfeuffer
2019-10-19 13:24:58 +02:00
parent a2c42060e5
commit d43080a3ea
3 changed files with 48 additions and 78 deletions

View File

@@ -0,0 +1,19 @@
package sonia.scm.web.lfs;
import org.eclipse.jgit.lfs.server.Response;
import sonia.scm.security.AccessToken;
import java.text.SimpleDateFormat;
import java.util.Collections;
@SuppressWarnings({"squid:S00116"})
// This class is used for json serialization, only
class ExpiringAction extends Response.Action {
public final String expires_at;
ExpiringAction(String href, AccessToken accessToken) {
this.expires_at = new SimpleDateFormat("yyyy-MM-dd'T'HH:MM:ss'Z'").format(accessToken.getExpiration());
this.href = href;
this.header = Collections.singletonMap("Authorization", "Bearer " + accessToken.compact());
}
}

View File

@@ -0,0 +1,74 @@
package sonia.scm.web.lfs;
import com.fasterxml.jackson.databind.ObjectMapper;
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;
import javax.inject.Inject;
import java.io.ByteArrayOutputStream;
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 ObjectMapper objectMapper;
private final String baseUrl;
@Inject
public LFSAuthCommand(AccessTokenBuilderFactory tokenBuilderFactory, GitRepositoryContextResolver gitRepositoryContextResolver, ScmConfiguration configuration) {
this.tokenBuilderFactory = tokenBuilderFactory;
this.gitRepositoryContextResolver = gitRepositoryContextResolver;
objectMapper = new ObjectMapper();
baseUrl = configuration.getBaseUrl();
}
@Override
public Optional<CommandInterpreter> canHandle(String command) {
return command.startsWith("git-lfs-authenticate") ? Optional.of(new CommandInterpreter() {
@Override
public String[] getParsedArgs() {
// we are interested only in the 'repo' argument, so we discard the rest
return new String[] {command.split("\\s+")[1]};
}
@Override
public ScmCommandProtocol getProtocolHandler() {
return (context, repositoryContext) -> {
ExpiringAction response = createResponse(repositoryContext);
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
objectMapper.writeValue(buffer, response);
context.getOutputStream().write(buffer.toString().getBytes());
};
}
private ExpiringAction createResponse(RepositoryContext repositoryContext) {
AccessToken accessToken = tokenBuilderFactory.create().expiresIn(5, TimeUnit.MINUTES).build();
Repository repository = repositoryContext.getRepository();
String url = format("%s/repo/%s/%s.git/info/lfs/", baseUrl, repository.getNamespace(), repository.getName());
return new ExpiringAction(url, accessToken);
}
@Override
public RepositoryContextResolver getRepositoryContextResolver() {
return gitRepositoryContextResolver;
}
}) : Optional.empty();
}
}

View File

@@ -12,11 +12,6 @@ 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;
/**
@@ -38,12 +33,14 @@ public class ScmBlobLfsRepository implements LargeFileRepository {
private final String baseUri;
private final Repository repository;
private AccessToken accessToken;
/**
* Creates a {@link ScmBlobLfsRepository} for the provided repository.
*
* @param repository
* @param repository The current scm repository this LFS repository is used for.
* @param blobStore The SCM Blobstore used for this @{@link LargeFileRepository}.
* @param tokenBuilderFactory
* @param tokenBuilderFactory The token builder used to create short lived access tokens.
* @param baseUri This URI is used to determine the actual URI for Upload / Download. Must be full URI (or
*/
@@ -97,26 +94,18 @@ 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.
ExpiringAction a = new ExpiringAction();
a.href = baseUri + id.getName();
return new ExpiringAction(baseUri + id.getName(), getAccessToken(scope));
}
AccessToken accessToken =
tokenBuilderFactory
private AccessToken getAccessToken(Scope scope) {
if (accessToken == null) {
accessToken = tokenBuilderFactory
.create()
.expiresIn(5, TimeUnit.MINUTES)
.scope(scope)
.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;
}
return accessToken;
}
@SuppressWarnings({"squid:ClassVariableVisibilityCheck", "squid:S00116"})
// This class is used for json serialization, only
private static class ExpiringAction extends Response.Action {
public String expires_at;
}
}