mirror of
https://github.com/scm-manager/scm-manager.git
synced 2025-11-03 03:55:51 +01:00
add push permissions to read access token
This is required because the read access token is used to obtain the write access token.
This commit is contained in:
@@ -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<CommandInterpreter> 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));
|
||||
};
|
||||
|
||||
@@ -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<String> 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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user