mirror of
https://github.com/scm-manager/scm-manager.git
synced 2026-02-23 15:00:49 +01:00
Guard import log
This commit is contained in:
@@ -24,7 +24,11 @@
|
||||
|
||||
package sonia.scm.importexport;
|
||||
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.store.DataStore;
|
||||
import sonia.scm.store.DataStoreFactory;
|
||||
|
||||
import javax.inject.Inject;
|
||||
@@ -45,7 +49,9 @@ public class RepositoryImportLoggerFactory {
|
||||
}
|
||||
|
||||
public void getLog(String logId, OutputStream out) {
|
||||
RepositoryImportLog log = dataStoreFactory.withType(RepositoryImportLog.class).withName("imports").build().getOptional(logId).orElseThrow(() -> new NotFoundException("Log", logId));
|
||||
DataStore<RepositoryImportLog> importStore = dataStoreFactory.withType(RepositoryImportLog.class).withName("imports").build();
|
||||
RepositoryImportLog log = importStore.getOptional(logId).orElseThrow(() -> new NotFoundException("Log", logId));
|
||||
checkPermission(log);
|
||||
PrintStream printStream = new PrintStream(out);
|
||||
log.toLogHeader().forEach(printStream::println);
|
||||
log.getEntries()
|
||||
@@ -53,4 +59,11 @@ public class RepositoryImportLoggerFactory {
|
||||
.map(RepositoryImportLog.Entry::toLogMessage)
|
||||
.forEach(printStream::println);
|
||||
}
|
||||
|
||||
private void checkPermission(RepositoryImportLog log) {
|
||||
Subject subject = SecurityUtils.getSubject();
|
||||
if (!subject.isPermitted("only:admin:allowed") && !subject.getPrincipal().toString().equals(log.getUserId())) {
|
||||
throw new AuthorizationException("not permitted");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@
|
||||
|
||||
package sonia.scm.importexport;
|
||||
|
||||
import org.apache.shiro.authz.AuthorizationException;
|
||||
import org.apache.shiro.subject.Subject;
|
||||
import org.apache.shiro.util.ThreadContext;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import sonia.scm.NotFoundException;
|
||||
import sonia.scm.store.InMemoryDataStore;
|
||||
@@ -33,26 +38,55 @@ import java.io.ByteArrayOutputStream;
|
||||
|
||||
import static org.assertj.core.api.Assertions.assertThat;
|
||||
import static org.junit.jupiter.api.Assertions.assertThrows;
|
||||
import static org.mockito.ArgumentMatchers.anyString;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
class RepositoryImportLoggerFactoryTest {
|
||||
|
||||
private final Subject subject = mock(Subject.class);
|
||||
|
||||
private final InMemoryDataStore<RepositoryImportLog> store = new InMemoryDataStore<>();
|
||||
private final RepositoryImportLoggerFactory factory = new RepositoryImportLoggerFactory(new InMemoryDataStoreFactory(store));
|
||||
|
||||
@BeforeEach
|
||||
void initSubject() {
|
||||
ThreadContext.bind(subject);
|
||||
}
|
||||
|
||||
@AfterEach
|
||||
void cleanupSubject() {
|
||||
ThreadContext.unbindSubject();
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReadLog() {
|
||||
RepositoryImportLog log = new RepositoryImportLog();
|
||||
log.setRepositoryType("git");
|
||||
log.setNamespace("hitchhiker");
|
||||
log.setName("HeartOfGold");
|
||||
log.setUserId("dent");
|
||||
log.setUserName("Arthur Dent");
|
||||
log.setSuccess(true);
|
||||
void shouldReadLogForExportingUser() {
|
||||
when(subject.getPrincipal()).thenReturn("dent");
|
||||
|
||||
log.addEntry(new RepositoryImportLog.Entry("import started"));
|
||||
log.addEntry(new RepositoryImportLog.Entry("import finished"));
|
||||
createLog();
|
||||
|
||||
store.put("42", log);
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
factory.getLog("42", out);
|
||||
|
||||
assertThat(out).asString().contains(
|
||||
"Import of repository hitchhiker/HeartOfGold",
|
||||
"Repository type: null",
|
||||
"Imported from: null",
|
||||
"Imported by dent (Arthur Dent)",
|
||||
"Finished successful"
|
||||
)
|
||||
.containsPattern(".+ - import started")
|
||||
.containsPattern(".+ - import finished");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldReadLogForAdmin() {
|
||||
when(subject.getPrincipal()).thenReturn("trillian");
|
||||
when(subject.isPermitted(anyString())).thenReturn(true);
|
||||
|
||||
createLog();
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
@@ -75,4 +109,31 @@ class RepositoryImportLoggerFactoryTest {
|
||||
|
||||
assertThrows(NotFoundException.class, () -> factory.getLog("42", out));
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldFailWithoutPermission() {
|
||||
when(subject.getPrincipal()).thenReturn("trillian");
|
||||
createLog();
|
||||
|
||||
doThrow(AuthorizationException.class).when(subject).checkPermission("only:admin:allowed");
|
||||
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||
|
||||
assertThrows(AuthorizationException.class, () -> factory.getLog("42", out));
|
||||
}
|
||||
|
||||
private void createLog() {
|
||||
RepositoryImportLog log = new RepositoryImportLog();
|
||||
log.setRepositoryType("git");
|
||||
log.setNamespace("hitchhiker");
|
||||
log.setName("HeartOfGold");
|
||||
log.setUserId("dent");
|
||||
log.setUserName("Arthur Dent");
|
||||
log.setSuccess(true);
|
||||
|
||||
log.addEntry(new RepositoryImportLog.Entry("import started"));
|
||||
log.addEntry(new RepositoryImportLog.Entry("import finished"));
|
||||
|
||||
store.put("42", log);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user