summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorg Pfuetzenreuter2022-05-08 04:16:19 +0200
committerGeorg Pfuetzenreuter2022-05-08 04:16:19 +0200
commitf105d0e1ab01fca7a04f54a8cacf6372a5b2d6c0 (patch)
tree3aa606b8f504acfece71f3cc2476b32afac0d42d
parent67ead5b62d0b1291bde0b49ac602be7cdcf3d536 (diff)
downloadpubsh-web-f105d0e1ab01fca7a04f54a8cacf6372a5b2d6c0.tar.gz
pubsh-web-f105d0e1ab01fca7a04f54a8cacf6372a5b2d6c0.tar.bz2
pubsh-web-f105d0e1ab01fca7a04f54a8cacf6372a5b2d6c0.zip
User/Admin logic
Signed-off-by: Georg Pfuetzenreuter <mail@georg-pfuetzenreuter.net>
-rw-r--r--src/main/java/net/libertacasa/pubsh/web/Docker.java42
-rw-r--r--src/main/java/net/libertacasa/pubsh/web/WebApplication.java78
-rw-r--r--src/main/resources/templates/user.html62
3 files changed, 167 insertions, 15 deletions
diff --git a/src/main/java/net/libertacasa/pubsh/web/Docker.java b/src/main/java/net/libertacasa/pubsh/web/Docker.java
index ccac8bf..00341a6 100644
--- a/src/main/java/net/libertacasa/pubsh/web/Docker.java
+++ b/src/main/java/net/libertacasa/pubsh/web/Docker.java
@@ -6,11 +6,14 @@ import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import com.github.dockerjava.api.DockerClient;
import com.github.dockerjava.api.command.BuildImageResultCallback;
import com.github.dockerjava.api.command.CreateContainerResponse;
+import com.github.dockerjava.api.command.ListContainersCmd;
+import com.github.dockerjava.api.command.ListImagesCmd;
import com.github.dockerjava.api.command.WaitContainerResultCallback;
import com.github.dockerjava.api.model.Image;
import com.github.dockerjava.core.DefaultDockerClientConfig;
@@ -44,15 +47,28 @@ public class Docker {
return imageList;
}
- public static List<Image> getImages() {
+ public static List<Image> getImages(String name) {
List<Image> imageQuery;
- imageQuery = dockerClient.listImagesCmd().exec();
+ ListImagesCmd imageQueryCmd = dockerClient.listImagesCmd();
+
+ if (name != null) {
+ imageQueryCmd.getFilters().put("reference", Arrays.asList(name + "*")); //to-do: filter by nameshX instead
+ }
+
+ imageQuery = imageQueryCmd.exec();
return imageQuery;
- }
+ }
- public static List<com.github.dockerjava.api.model.Container> getContainers() {
- List<com.github.dockerjava.api.model.Container> containerQuery;
- containerQuery = dockerClient.listContainersCmd().withShowAll(true).exec();
+ public static List<com.github.dockerjava.api.model.Container> getContainers(String name) {
+ List<com.github.dockerjava.api.model.Container> containerQuery;
+ ListContainersCmd containerQueryCmd = dockerClient.listContainersCmd();
+
+ if (name != null) {
+ containerQueryCmd.getFilters().put("name", Arrays.asList(name + "*"));
+ }
+
+ containerQuery = containerQueryCmd.withShowAll(true).exec();
+
return containerQuery;
}
@@ -99,11 +115,19 @@ public class Docker {
}
public static void deleteImage(String username, String id) {
- List<Image> imagequery = Docker.getImages();
+ List<Image> imagequery = Docker.getImages(null);
if (imagequery.toString().contains(id)) {
- System.out.printf("Found image ID %s, deleting ...\n", id);
- dockerClient.removeImageCmd(id).withImageId(id).exec();
+ try {
+ System.out.printf("Found image ID %s, deleting ...\n", id);
+ dockerClient.removeImageCmd(id).withImageId(id).exec();
+ } catch (com.github.dockerjava.api.exception.ConflictException exception) {
+ System.out.println("Image is still being used by a container.");
+ throw exception;
+ }
+ //needs to wait for callback, but there is none
+ //System.out.printf("%s", removeQuery);
+
}
if (! imagequery.toString().contains(id)) {
System.out.printf("Image ID %s not found.\n", id);
diff --git a/src/main/java/net/libertacasa/pubsh/web/WebApplication.java b/src/main/java/net/libertacasa/pubsh/web/WebApplication.java
index ec3fbc8..d4094f6 100644
--- a/src/main/java/net/libertacasa/pubsh/web/WebApplication.java
+++ b/src/main/java/net/libertacasa/pubsh/web/WebApplication.java
@@ -33,6 +33,8 @@ import com.github.dockerjava.api.model.Image;
@Controller
public class WebApplication {
+ static ArrayList<String> availableOs = new ArrayList<String>();
+
public static void main(String[] args) {
SpringApplication.run(WebApplication.class, args);
}
@@ -44,7 +46,7 @@ public class WebApplication {
}
@GetMapping("/portal")
- public String portal(Model model) {
+ public String portal(Model model) throws pubshError {
KeycloakAuthenticationToken authentication = (KeycloakAuthenticationToken)
SecurityContextHolder.getContext().getAuthentication();
@@ -52,14 +54,21 @@ public class WebApplication {
String username="";
String email="";
String attribute01="";
-
+
+ if (! (principal instanceof KeycloakPrincipal)) {
+ System.out.println("Fatal: received logon without Keycloak principal.");
+ throw new pubshError("Invalid request.");
+ }
if (principal instanceof KeycloakPrincipal) {
KeycloakPrincipal<?> kPrincipal = (KeycloakPrincipal<?>) principal;
IDToken token = kPrincipal.getKeycloakSecurityContext().getIdToken();
//System.out.println("Token: " + token);
Map<String, Object> customClaims = token.getOtherClaims();
-
+ if (! customClaims.containsKey("username")) {
+ System.out.println("Fatal: received logon without username.");
+ throw new pubshError("Invalid request.");
+ }
if (customClaims.containsKey("email")) {
email = String.valueOf(customClaims.get("email"));
}
@@ -75,9 +84,10 @@ public class WebApplication {
model.addAttribute("attribute01", attribute01);
}
- List<Image> images = Docker.getImages();
+ List<Image> images = Docker.getImages(null);
+
//System.out.println(images);
- List<Container> containers = Docker.getContainers();
+ List<Container> containers = Docker.getContainers(null);
//System.out.println(containers);
model.addAttribute("docker_images", images);
@@ -94,6 +104,51 @@ public class WebApplication {
return("portal");
}
+ @GetMapping("/user")
+ public String user(Model model) throws pubshError {
+ KeycloakAuthenticationToken authentication = (KeycloakAuthenticationToken)
+ SecurityContextHolder.getContext().getAuthentication();
+ Principal principal = (Principal) authentication.getPrincipal();
+ String username="";
+ String email="";
+ String attribute01="";
+ if (! (principal instanceof KeycloakPrincipal)) {
+ System.out.println("Fatal: received logon without Keycloak principal.");
+ throw new pubshError("Invalid request.");
+ }
+ if (principal instanceof KeycloakPrincipal) {
+ KeycloakPrincipal<?> kPrincipal = (KeycloakPrincipal<?>) principal;
+ IDToken token = kPrincipal.getKeycloakSecurityContext().getIdToken();
+ Map<String, Object> customClaims = token.getOtherClaims();
+ if (! customClaims.containsKey("username")) {
+ System.out.println("Fatal: received logon without username.");
+ throw new pubshError("Invalid request.");
+ }
+ if (customClaims.containsKey("email")) {
+ email = String.valueOf(customClaims.get("email"));
+ }
+ if (customClaims.containsKey("username")) {
+ username = String.valueOf(customClaims.get("username"));
+ }
+ if (customClaims.containsKey("attribute01")) {
+ attribute01 = String.valueOf(customClaims.get("attribute01"));
+ }
+ model.addAttribute("username", username);
+ model.addAttribute("principalid", principal.getName());
+ model.addAttribute("email", email);
+ model.addAttribute("attribute01", attribute01);
+ }
+
+ List<Image> images = Docker.getImages(username);
+ List<Container> containers = Docker.getContainers(username);
+
+ model.addAttribute("docker_images", images);
+ model.addAttribute("docker_containers", containers);
+ model.addAttribute("availableOs", availableOs);
+
+ return("user");
+ }
+
@DeleteMapping("/frontend/container/delete/{id}")
public static String deleteContainer(@PathVariable String id, HttpServletRequest request, RedirectAttributes redirectAttributes) {
// [Start] This block should move to a logging method. It's only job is to print user details to the console.
@@ -184,5 +239,16 @@ public class WebApplication {
private RefreshableKeycloakSecurityContext getKeycloakSecurityContext(HttpServletRequest request){
return (RefreshableKeycloakSecurityContext) request.getAttribute(KeycloakSecurityContext.class.getName());
- }
+ }
+
+ public class pubshError extends Exception
+ {
+ private static final long serialVersionUID = 1L;
+
+ public pubshError(String message)
+ {
+ super(message);
+ }
+ }
+
}
diff --git a/src/main/resources/templates/user.html b/src/main/resources/templates/user.html
new file mode 100644
index 0000000..a5473ee
--- /dev/null
+++ b/src/main/resources/templates/user.html
@@ -0,0 +1,62 @@
+<!DOCTYPE html>
+<html xmlns:th="http://www.thymeleaf.org">
+<head th:include="layout :: headerFragment">
+</head>
+<body>
+ <div id="container">
+ <div th:if="${message}" th:text="${message}" th:class="${'alert ' + alertClass}"/></div>
+ <h1>
+ Hello, <span th:text="${username}"></span>.
+ </h1>
+ <div th:if="${attribute01 != null}" th:text="${attribute01}"></div>
+ <h2>Available images:</h2>
+ <table>
+ <tr th:each="image: ${docker_images}" th:if="${image.repoTags[0] != '<none>:<none>'}">
+ <td>
+ <table>
+ <tr th:each="tag: ${image.repoTags}">
+ <td th:text="${tag}"/>
+ <td>
+ <form id="deletion_pseudoform" action="#" th:action="@{'/frontend/image/delete/{id}'(id=${tag})}" th:method="delete" th:tag="${tag}" th:onsubmit="return confirm('Do you really want to delete the imag with tag ' + this.getAttribute('tag') + '?');">
+ <button class="btn btn-danger" id="deletion_submission" type="submit">x</button>
+ </form>
+ </td>
+ </tr>
+ </table>
+ </td>
+ <td th:text="${image.created}" />
+ </tr>
+ </table>
+
+ <h2>Generate new throw-away shell:</h2>
+ <form th:object="${osChoice}" th:id="request_pseudoform" action="#" th:action="@{'/frontend/container/add'}" th:method="post" th:os="${osChoice}" th:onsubmit="return confirm('You are about to generate a shell with the OS ' + this.getAttribute('osoption') + ' - please be patient after you confirm, as the generation may take a short while.');">
+ <select class="form-control" th:object="${osChoice}" name="osChoice">
+ <option value="">Select operating system ...</option>
+ <option
+ th:each="osoption : ${availableOs}"
+ th:value="${osoption}"
+ th:attr="value=${osoption}"
+ th:text="${osoption}"></option>
+ </select>
+ <button class="btn btn-primary" th:id="request_submission" th:type="submit">Generate</button>
+ </form>
+
+ <h2>Existing containers:</h2>
+ <table>
+ <tr th:each="container: ${docker_containers}">
+ <td th:text="${container.names[0]}" />
+ <td th:text="${container.image}" />
+ <td th:text="${container.id}" />
+ <td th:text="${container.status}" />
+<td>
+<form id="deletion_pseudoform" action="#" th:action="@{'/frontend/container/delete/{id}'(id=${container.id})}" th:method="delete" th:containerid="${container.id}" th:containerShaSum="${container.imageId}" th:onsubmit="return confirm('Do you really want to delete the container with ID ' + this.getAttribute('containerid') + ' which is attached to the image with checksum ' + this.getAttribute('containerShaSum') + ' ?');">
+<button class="btn btn-danger" id="deletion_submission" type="submit">Delete</button>
+</form>
+</td>
+ </tr>
+ </table>
+ <p></p>
+ <a href="/logout">Logout</a>
+ </div>
+</body>
+</html>