Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ssh and token authentication #346

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,24 @@ dependencies {
implementation "commons-io:commons-io:2.18.0"
implementation "com.thedeanda:lorem:2.2"
implementation "org.eclipse.jgit:org.eclipse.jgit:7.1.0.202411261347-r"
// https://search.maven.org/artifact/org.eclipse.jgit/org.eclipse.jgit
implementation "org.eclipse.jgit:org.eclipse.jgit.ssh.apache:7.1.0.202411261347-r"
// Note: jgit.htt.server is not compatible with jakarta yet and neither is there a timeline. Hence, we had to add the source files to our repository.
// Once the compatibility is given, we can switch back to the maven dependency.
implementation "org.eclipse.jgit:org.eclipse.jgit.http.server:7.1.0.202411261347-r"

// apache ssh enabled the ssh git operations in LocalVC together with JGit
implementation "org.apache.sshd:sshd-core:2.14.0"
implementation "org.apache.sshd:sshd-git:2.14.0"
implementation "org.apache.sshd:sshd-osgi:2.14.0"
implementation "org.apache.sshd:sshd-sftp:2.14.0"

implementation "org.bouncycastle:bcpkix-jdk18on:1.79"
implementation "org.bouncycastle:bcprov-jdk18on:1.79"

implementation "io.reactivex.rxjava3:rxjava:3.1.8"
implementation 'io.netty:netty-resolver-dns-native-macos:4.1.100.Final:osx-aarch_64'
implementation "org.eclipse.jgit:org.eclipse.jgit:7.1.0.202411261347-r"
implementation "io.reactivex.rxjava3:rxjava:3.1.10"
implementation 'io.netty:netty-resolver-dns-native-macos:4.1.116.Final:osx-aarch_64'
implementation 'com.opencsv:opencsv:5.9'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package de.tum.cit.aet.artemisModel;

public enum ArtemisAuthMechanism {
ONLINE_IDE,
PASSWORD,
PARTICIPATION_TOKEN,
SSH,
USER_TOKEN,
}
43 changes: 43 additions & 0 deletions src/main/java/de/tum/cit/aet/domain/ArtemisUser.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,21 @@
import com.opencsv.bean.CsvBindByName;
import de.tum.cit.aet.util.ArtemisServer;
import jakarta.persistence.*;
import java.io.ByteArrayOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.security.*;
import java.security.interfaces.RSAPublicKey;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.Base64;
import org.bouncycastle.openssl.jcajce.JcaPEMWriter;
import org.bouncycastle.util.io.pem.PemObject;
import org.bouncycastle.util.io.pem.PemWriter;
import org.springframework.data.util.Pair;

@Entity
@Table(name = "artemis_user")
Expand Down Expand Up @@ -35,6 +49,14 @@ public class ArtemisUser {
@JsonIgnore
private ZonedDateTime tokenExpirationDate;

@Column(name = "public_ssh_key")
@JsonIgnore
private String publicKey;

@Column(name = "private_ssh_key")
@JsonIgnore
private String privateKey;

public Long getId() {
return id;
}
Expand Down Expand Up @@ -90,4 +112,25 @@ public ZonedDateTime getTokenExpirationDate() {
public void setTokenExpirationDate(ZonedDateTime tokenExpirationDate) {
this.tokenExpirationDate = tokenExpirationDate;
}

public String getPrivateKey() {
return privateKey;
}

public void setPrivateKey(String privateKey) {
this.privateKey = privateKey;
}

public String getPublicKey() {
return publicKey;
}

public void setPublicKey(String publicKey) {
this.publicKey = publicKey;
}

public void setKeyPair(Pair<String, String> keyPair) {
this.publicKey = keyPair.getFirst();
this.privateKey = keyPair.getSecond();
}
}
8 changes: 8 additions & 0 deletions src/main/java/de/tum/cit/aet/domain/RequestType.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,12 @@ public enum RequestType {
REPOSITORY_INFO,
REPOSITORY_FILES,
MISC,
SETUP_SSH_KEYS,
FETCH_PARTICIPATION_VCS_ACCESS_TOKEN,
CLONE_SSH,
CLONE_TOKEN,
CLONE_PASSWORD,
PUSH_SSH,
PUSH_TOKEN,
PUSH_PASSWORD,
}
50 changes: 50 additions & 0 deletions src/main/java/de/tum/cit/aet/domain/Simulation.java
Original file line number Diff line number Diff line change
Expand Up @@ -45,10 +45,24 @@ public class Simulation {
@Column(name = "user_range")
private String userRange;

@Deprecated
jfr2102 marked this conversation as resolved.
Show resolved Hide resolved
@JsonIgnore
@Enumerated(EnumType.STRING)
@Column(name = "ide_type", nullable = false)
private IDEType ideType;

@Column(name = "onlineide_percentage", nullable = false)
private double onlineIdePercentage;

@Column(name = "password_percentage", nullable = false)
private double passwordPercentage;

@Column(name = "token_percentage", nullable = false)
private double tokenPercentage;

@Column(name = "ssh_percentage", nullable = false)
private double sshPercentage;

@Column(name = "number_of_commits_and_pushes_from")
private int numberOfCommitsAndPushesFrom;

Expand Down Expand Up @@ -212,6 +226,42 @@ public boolean instructorCredentialsProvided() {
return instructorUsername != null && instructorPassword != null;
}

public double getOnlineIdePercentage() {
return onlineIdePercentage;
}

public void setOnlineIdePercentage(double onlineIdePercentage) {
this.onlineIdePercentage = onlineIdePercentage;
}

public double getPasswordPercentage() {
return passwordPercentage;
}

public void setPasswordPercentage(double passwordPercentage) {
this.passwordPercentage = passwordPercentage;
}

public double getTokenPercentage() {
return tokenPercentage;
}

public void setTokenPercentage(double tokenPercentage) {
this.tokenPercentage = tokenPercentage;
}

public double getSshPercentage() {
return sshPercentage;
}

public void setSshPercentage(double sshPercentage) {
this.sshPercentage = sshPercentage;
}

public boolean participationPercentagesSumUpToHundredPercent() {
return (this.onlineIdePercentage + this.passwordPercentage + this.tokenPercentage + this.sshPercentage) == 100.0;
}

public enum Mode {
/**
* We create a temporary course and exam, prepare the exam and delete everything afterwards.
Expand Down
6 changes: 5 additions & 1 deletion src/main/java/de/tum/cit/aet/service/CiStatusService.java
Original file line number Diff line number Diff line change
Expand Up @@ -134,18 +134,22 @@ public CompletableFuture<Void> subscribeToCiStatusViaResults(SimulationRun simul
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
log.debug("Updating CI status for simulation run {}", simulationRun.getId());
log.info("Updating CI status for simulation run {}", simulationRun.getId());

submissions = new ArrayList<>();
for (var participation : participations) {
submissions.addAll(admin.getSubmissions(participation.getId()));
}
numberOfQueuedJobs = submissions.size() - getNumberOfResults(submissions);
log.info("Currently queued buildjobs: {}", numberOfQueuedJobs);

status.setQueuedJobs(numberOfQueuedJobs);
status.setTimeInMinutes(status.getTimeInMinutes() + 1);
status.setAvgJobsPerMinute((double) (status.getTotalJobs() - status.getQueuedJobs()) / status.getTimeInMinutes());
status = ciStatusRepository.save(status);
websocketService.sendRunCiUpdate(simulationRun.getId(), status);
} while (numberOfQueuedJobs > 0);

status.setFinished(true);
status = ciStatusRepository.save(status);
websocketService.sendRunCiUpdate(simulationRun.getId(), status);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,15 @@
import de.tum.cit.aet.service.dto.ArtemisUserPatternDTO;
import de.tum.cit.aet.util.ArtemisServer;
import de.tum.cit.aet.util.NumberRangeParser;
import de.tum.cit.aet.util.SshUtils;
import de.tum.cit.aet.web.rest.errors.BadRequestAlertException;
import java.io.*;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.IntStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.util.Pair;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

Expand Down Expand Up @@ -68,6 +72,21 @@ public List<ArtemisUser> createArtemisUsersByPattern(ArtemisServer server, Artem
);
simulatedArtemisAdmin.login();
}
log.info("Generate SSH keys... this might take some time");
AtomicInteger sshKeyCounter = new AtomicInteger(0);
int totalKeys = pattern.getTo() - pattern.getFrom();
Pair<String, String>[] pregeneratedSSHkeys = new Pair[totalKeys + 1];

IntStream.range(pattern.getFrom(), pattern.getTo() + 1)
.parallel()
.forEach(i -> {
if (sshKeyCounter.get() % 100 == 0) {
log.info("{{}} of {{}} keys created...", sshKeyCounter.get(), totalKeys);
}
pregeneratedSSHkeys[i - pattern.getFrom()] = SshUtils.generateSshKeyPair();
sshKeyCounter.getAndIncrement();
});
log.info("Done generating {{}} SSH keys", totalKeys);

List<ArtemisUser> createdUsers = new ArrayList<>();
for (int i = pattern.getFrom(); i < pattern.getTo(); i++) {
Expand All @@ -78,6 +97,8 @@ public List<ArtemisUser> createArtemisUsersByPattern(ArtemisServer server, Artem
var password = pattern.getPasswordPattern().replace("{i}", String.valueOf(i));
artemisUser.setUsername(username);
artemisUser.setPassword(password);
artemisUser.setKeyPair(pregeneratedSSHkeys[i - pattern.getFrom()]);

try {
ArtemisUser createdUser = saveArtemisUser(artemisUser);
// Create user on Artemis if necessary
Expand Down Expand Up @@ -111,6 +132,7 @@ public ArtemisUser createArtemisUser(ArtemisServer server, ArtemisUserForCreatio
artemisUser.setServer(server);
artemisUser.setUsername(artemisUserDTO.getUsername());
artemisUser.setPassword(artemisUserDTO.getPassword());
artemisUser.setKeyPair(SshUtils.generateSshKeyPair());

if (artemisUserDTO.getServerWideId() != null) {
artemisUser.setServerWideId(artemisUserDTO.getServerWideId());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,32 @@ public Course createCourse() {
.block();
}

public void cancelAllQueuedBuildJobs() {
if (!authenticated) {
throw new IllegalStateException("User " + username + " is not logged in or does not have the necessary access rights.");
}

webClient
.delete()
.uri(uriBuilder -> uriBuilder.pathSegment("api", "admin", "cancel-all-queued-jobs").build())
.retrieve()
.toBodilessEntity()
.block();
}

public void cancelAllRunningBuildJobs() {
if (!authenticated) {
throw new IllegalStateException("User " + username + " is not logged in or does not have the necessary access rights.");
}

webClient
.delete()
.uri(uriBuilder -> uriBuilder.pathSegment("api", "admin", "cancel-all-running-jobs").build())
.retrieve()
.toBodilessEntity()
.block();
}

/**
* Create an exam for benchmarking.
* @param course the course for which to create the exam
Expand Down
Loading
Loading