diff options
author | Georg Pfuetzenreuter | 2022-05-08 04:16:19 +0200 |
---|---|---|
committer | Georg Pfuetzenreuter | 2022-05-08 04:16:19 +0200 |
commit | f105d0e1ab01fca7a04f54a8cacf6372a5b2d6c0 (patch) | |
tree | 3aa606b8f504acfece71f3cc2476b32afac0d42d | |
parent | 67ead5b62d0b1291bde0b49ac602be7cdcf3d536 (diff) | |
download | pubsh-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.java | 42 | ||||
-rw-r--r-- | src/main/java/net/libertacasa/pubsh/web/WebApplication.java | 78 | ||||
-rw-r--r-- | src/main/resources/templates/user.html | 62 |
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> |