diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LFSAuthCommand.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LFSAuthCommand.java index 42dd7226b9..02f461bc5c 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LFSAuthCommand.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LFSAuthCommand.java @@ -2,6 +2,8 @@ package sonia.scm.web.lfs; import com.fasterxml.jackson.databind.ObjectMapper; import com.google.common.base.Charsets; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.config.ScmConfiguration; import sonia.scm.plugin.Extension; import sonia.scm.protocolcommand.CommandInterpreter; @@ -22,6 +24,8 @@ import static java.lang.String.format; @Extension public class LFSAuthCommand implements CommandInterpreterFactory { + private static final Logger LOG = LoggerFactory.getLogger(LFSAuthCommand.class); + private static final String LFS_INFO_URL_PATTERN = "%s/repo/%s/%s.git/info/lfs/"; private final LfsAccessTokenFactory tokenFactory; @@ -41,6 +45,7 @@ public class LFSAuthCommand implements CommandInterpreterFactory { @Override public Optional canHandle(String command) { if (command.startsWith("git-lfs-authenticate")) { + LOG.trace("create command for input: {}", command); return Optional.of(new LfsAuthCommandInterpreter(command)); } else { return Optional.empty(); @@ -65,6 +70,8 @@ public class LFSAuthCommand implements CommandInterpreterFactory { public ScmCommandProtocol getProtocolHandler() { return (context, repositoryContext) -> { ExpiringAction response = createResponseObject(repositoryContext); + // we buffer the response and write it with a single write, + // because otherwise the ssh connection is not closed String buffer = serializeResponse(response); context.getOutputStream().write(buffer.getBytes(Charsets.UTF_8)); }; diff --git a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LfsAccessTokenFactory.java b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LfsAccessTokenFactory.java index 272d70fd6c..ba24d0fd35 100644 --- a/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LfsAccessTokenFactory.java +++ b/scm-plugins/scm-git-plugin/src/main/java/sonia/scm/web/lfs/LfsAccessTokenFactory.java @@ -1,16 +1,24 @@ package sonia.scm.web.lfs; +import com.github.sdorra.ssp.PermissionCheck; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.repository.Repository; import sonia.scm.repository.RepositoryPermissions; import sonia.scm.security.AccessToken; import sonia.scm.security.AccessTokenBuilderFactory; +import sonia.scm.security.Permission; import sonia.scm.security.Scope; import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; import java.util.concurrent.TimeUnit; public class LfsAccessTokenFactory { + private static final Logger LOG = LoggerFactory.getLogger(LfsAccessTokenFactory.class); + private final AccessTokenBuilderFactory tokenBuilderFactory; @Inject @@ -19,29 +27,44 @@ public class LfsAccessTokenFactory { } AccessToken createReadAccessToken(Repository repository) { - RepositoryPermissions.pull(repository).check(); - RepositoryPermissions.read(repository).check(); - return createToken( - Scope.valueOf( - RepositoryPermissions.read(repository).asShiroString(), - RepositoryPermissions.pull(repository).asShiroString())); + PermissionCheck read = RepositoryPermissions.read(repository); + read.check(); + + PermissionCheck pull = RepositoryPermissions.pull(repository); + pull.check(); + + List permissions = new ArrayList<>(); + permissions.add(read.asShiroString()); + permissions.add(pull.asShiroString()); + + PermissionCheck push = RepositoryPermissions.push(repository); + if (push.isPermitted()) { + // we have to add push permissions, + // because this token is also used to obtain the write access token + permissions.add(push.asShiroString()); + } + + return createToken(Scope.valueOf(permissions)); } AccessToken createWriteAccessToken(Repository repository) { - RepositoryPermissions.read(repository).check(); - RepositoryPermissions.pull(repository).check(); - RepositoryPermissions.push(repository).check(); - return createToken( - Scope.valueOf( - RepositoryPermissions.read(repository).asShiroString(), - RepositoryPermissions.pull(repository).asShiroString(), - RepositoryPermissions.push(repository).asShiroString())); + PermissionCheck read = RepositoryPermissions.read(repository); + read.check(); + + PermissionCheck pull = RepositoryPermissions.pull(repository); + pull.check(); + + PermissionCheck push = RepositoryPermissions.push(repository); + push.check(); + + return createToken(Scope.valueOf(read.asShiroString(), pull.asShiroString(), push.asShiroString())); } private AccessToken createToken(Scope scope) { + LOG.trace("create access token with scope: {}", scope); return tokenBuilderFactory .create() - .expiresIn(1, TimeUnit.MINUTES) + .expiresIn(5, TimeUnit.MINUTES) .scope(scope) .build(); } 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 c646a194b7..b70b948c9b 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 @@ -2,14 +2,13 @@ package sonia.scm.web.lfs; import org.eclipse.jgit.lfs.lib.AnyLongObjectId; import org.eclipse.jgit.lfs.server.LargeFileRepository; -import org.eclipse.jgit.lfs.server.Response; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.repository.Repository; import sonia.scm.security.AccessToken; import sonia.scm.store.Blob; import sonia.scm.store.BlobStore; -import java.io.IOException; - /** * This LargeFileRepository is used for jGit-Servlet implementation. Under the jgit LFS Servlet hood, the * SCM-Repository API is used to implement the Repository. @@ -19,6 +18,8 @@ import java.io.IOException; */ public class ScmBlobLfsRepository implements LargeFileRepository { + private static final Logger LOG = LoggerFactory.getLogger(ScmBlobLfsRepository.class); + private final BlobStore blobStore; private final LfsAccessTokenFactory tokenFactory; @@ -54,6 +55,7 @@ public class ScmBlobLfsRepository implements LargeFileRepository { @Override public ExpiringAction getDownloadAction(AnyLongObjectId id) { if (accessToken == null) { + LOG.trace("create access token to download lfs object {} from repository {}", id, repository.getNamespaceAndName()); accessToken = tokenFactory.createReadAccessToken(repository); } return getAction(id, accessToken); @@ -62,6 +64,7 @@ public class ScmBlobLfsRepository implements LargeFileRepository { @Override public ExpiringAction getUploadAction(AnyLongObjectId id, long size) { if (accessToken == null) { + LOG.trace("create access token to upload lfs object {} to repository {}", id, repository.getNamespaceAndName()); accessToken = tokenFactory.createWriteAccessToken(repository); } return getAction(id, accessToken); 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 cc79d8e5c4..3b200ade36 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 @@ -4,6 +4,8 @@ import com.google.common.annotations.VisibleForTesting; import org.eclipse.jgit.lfs.server.LargeFileRepository; import org.eclipse.jgit.lfs.server.LfsProtocolServlet; import org.eclipse.jgit.lfs.server.fs.FileLfsServlet; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import sonia.scm.repository.Repository; import sonia.scm.store.BlobStore; import sonia.scm.util.HttpUtil; @@ -26,6 +28,8 @@ import javax.servlet.http.HttpServletRequest; @Singleton public class LfsServletFactory { + private static final Logger LOG = LoggerFactory.getLogger(LfsServletFactory.class); + private final LfsBlobStoreFactory lfsBlobStoreFactory; private final LfsAccessTokenFactory tokenFactory; @@ -43,6 +47,7 @@ public class LfsServletFactory { * @return The {@link LfsProtocolServlet} to provide the LFS Batch API for a SCM Repository. */ public LfsProtocolServlet createProtocolServletFor(Repository repository, HttpServletRequest request) { + LOG.trace("create lfs protocol servlet for repository {}", repository.getNamespaceAndName()); BlobStore blobStore = lfsBlobStoreFactory.getLfsBlobStore(repository); String baseUri = buildBaseUri(repository, request); @@ -58,6 +63,7 @@ public class LfsServletFactory { * @return The {@link FileLfsServlet} to provide the LFS Upload / Download API for a SCM Repository. */ public HttpServlet createFileLfsServletFor(Repository repository, HttpServletRequest request) { + LOG.trace("create lfs file servlet for repository {}", repository.getNamespaceAndName()); return new ScmFileTransferServlet(lfsBlobStoreFactory.getLfsBlobStore(repository)); }