Skip to content

Commit

Permalink
- Use Thymeleaf layout lib to use header and content pages
Browse files Browse the repository at this point in the history
- Introduce runtime environment to move it away from html
  • Loading branch information
nbaars committed Nov 29, 2021
1 parent 47e3ed8 commit a3c9797
Show file tree
Hide file tree
Showing 27 changed files with 293 additions and 104 deletions.
5 changes: 5 additions & 0 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>nz.net.ultraq.thymeleaf</groupId>
<artifactId>thymeleaf-layout-dialect</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/org/owasp/wrongsecrets/AllControllerAdvice.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.owasp.wrongsecrets;

import org.owasp.wrongsecrets.challenges.Challenge;
import org.owasp.wrongsecrets.challenges.ChallengeUI;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ModelAttribute;

import java.util.List;

/**
* Make sure shared model properties are always set for each controller. So for example `challenges` should be present
* in the model instead of adding it in all endpoint we can use this advice to let Spring do this for us.
*/
@ControllerAdvice
public class AllControllerAdvice {

private final List<ChallengeUI> challenges;
private final String version;
private RuntimeEnvironment runtimeEnvironment;

public AllControllerAdvice(List<Challenge> challenges, @Value("${APP_VERSION}") String version, RuntimeEnvironment runtimeEnvironment) {
this.challenges = ChallengeUI.toUI(challenges, runtimeEnvironment);
this.version = version;
this.runtimeEnvironment = runtimeEnvironment;
}

@ModelAttribute
public void addChallenges(Model model) {
model.addAttribute("challenges", challenges);
}

@ModelAttribute
public void addVersion(Model model) {
model.addAttribute("version", version);
}

@ModelAttribute
public void addRuntimeEnviroment(Model model) {
model.addAttribute("environment", runtimeEnvironment);
}

@Bean
public List<ChallengeUI> uiChallenges() {
return challenges;
}
}
39 changes: 10 additions & 29 deletions src/main/java/org/owasp/wrongsecrets/IndexController.java
Original file line number Diff line number Diff line change
@@ -1,44 +1,25 @@
package org.owasp.wrongsecrets;

import lombok.extern.slf4j.Slf4j;
import org.owasp.wrongsecrets.challenges.Challenge;
import org.owasp.wrongsecrets.challenges.ChallengeUI;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;

import java.util.List;

@Controller
@Slf4j
public class IndexController {

private final String k8sEnvironment;
private final String version;
private final List<ChallengeUI> challenges;

public IndexController(@Value("${K8S_ENV}") String k8sEnvironment, @Value("${APP_VERSION}") String version, List<Challenge> challenges) {
this.k8sEnvironment = k8sEnvironment;
this.version = version;
this.challenges = ChallengeUI.toUI(challenges, k8sEnvironment);
}

@GetMapping("/")
public String index(Model model) {
model.addAttribute("page", "index");
model.addAttribute("challenges", challenges);
model.addAttribute("version", version);
model.addAttribute("environment", k8sEnvironment);
if ("gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
model.addAttribute("cloud", "enabled");
}
if ("k8s-with-vault".equals(k8sEnvironment) || "gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
model.addAttribute("vault", "enabled");
}
if (k8sEnvironment.contains("k8s") || "gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
model.addAttribute("k8s", "enabled");
}
return "index";
// if ("gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
// model.addAttribute("cloud", "enabled");
// }
// if ("k8s-with-vault".equals(k8sEnvironment) || "gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
// model.addAttribute("vault", "enabled");
// }
// if (k8sEnvironment.contains("k8s") || "gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
// model.addAttribute("k8s", "enabled");
// }
return "welcome";
}
}
2 changes: 2 additions & 0 deletions src/main/java/org/owasp/wrongsecrets/MvcConfiguration.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package org.owasp.wrongsecrets;

import nz.net.ultraq.thymeleaf.layoutdialect.LayoutDialect;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
Expand Down Expand Up @@ -43,6 +44,7 @@ public SpringTemplateEngine thymeleafTemplateEngine(ITemplateResolver springThym
AsciiDoctorTemplateResolver asciiDoctorTemplateResolver) {
SpringTemplateEngine engine = new SpringTemplateEngine();
engine.setEnableSpringELCompiler(true);
engine.addDialect(new LayoutDialect());
engine.setTemplateResolvers(
Set.of(asciiDoctorTemplateResolver, springThymeleafTemplateResolver));
return engine;
Expand Down
42 changes: 42 additions & 0 deletions src/main/java/org/owasp/wrongsecrets/RuntimeEnvironment.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package org.owasp.wrongsecrets;

import org.owasp.wrongsecrets.challenges.Challenge;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Component
public class RuntimeEnvironment {

public enum Environment {
DOCKER("Docker"), GCP("gcp"), AWS("aws"), VAULT("k8s-with-vault"), K8S("k8s");

private final String id;

Environment(String id) {
this.id = id;
}

static Environment fromId(String id) {
return Arrays.asList(Environment.values()).stream().filter(e -> e.id.equals(id)).findAny().get();
}
}

private final Environment runtimeEnvironment;

@Autowired
public RuntimeEnvironment(@Value("${K8S_ENV}") String currentRuntimeEnvironment) {
this.runtimeEnvironment = Environment.fromId(currentRuntimeEnvironment);
}

public RuntimeEnvironment(Environment runtimeEnvironment) {
this.runtimeEnvironment = runtimeEnvironment;
}

public boolean environmentIsFitFor(Challenge challenge) {
return challenge.supportedRuntimeEnvironments().contains(runtimeEnvironment);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ public class SecretsErrorController implements ErrorController {

@RequestMapping("/error")
public String handleError(Model model) {
model.addAttribute("page", "error");
return "index";
return "error";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,6 @@ public InMemoryScoreCard scoreCard() {
return new InMemoryScoreCard(11);
}



}
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.owasp.wrongsecrets.RuntimeEnvironment.Environment;
import org.owasp.wrongsecrets.ScoreCard;

import java.util.List;

@RequiredArgsConstructor
@Getter
public abstract class Challenge {
Expand All @@ -26,4 +29,6 @@ public boolean solved(String answer) {
public boolean environmentSupported() {
return false;
}

public abstract List<Environment> supportedRuntimeEnvironments();
}
42 changes: 35 additions & 7 deletions src/main/java/org/owasp/wrongsecrets/challenges/ChallengeUI.java
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import lombok.Getter;
import org.asciidoctor.Asciidoctor;
import org.owasp.wrongsecrets.RuntimeEnvironment;

import java.util.List;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import static org.owasp.wrongsecrets.challenges.ChallengeEnvironment.CLOUD;

Expand All @@ -17,14 +19,14 @@ public class ChallengeUI {
private static final Asciidoctor asciidoctor = Asciidoctor.Factory.create();
private static final Pattern challengePattern = Pattern.compile("(\\D+)(\\d+)");

private Challenge challenge;
private int challengeNumber;
private String environment;
private final Challenge challenge;
private final int challengeNumber;
private final RuntimeEnvironment runtimeEnvironment;

public ChallengeUI(Challenge challenge, int challengeNumber, String environment) {
public ChallengeUI(Challenge challenge, int challengeNumber, RuntimeEnvironment runtimeEnvironment) {
this.challenge = challenge;
this.challengeNumber = challengeNumber;
this.environment = environment;
this.runtimeEnvironment = runtimeEnvironment;
}

public String getName() {
Expand All @@ -41,12 +43,38 @@ public Integer getLink() {

public String getExplanation() {
var name = this.getChallenge().getClass().getSimpleName().toLowerCase();
var env = challenge.getEnvironment() == CLOUD && environment.equals("gcp") ? "-gcp" : "";
var env = challenge.getEnvironment() == CLOUD && runtimeEnvironment.equals("gcp") ? "-gcp" : "";

return String.format("%s%s", name, env);
}

public static List<ChallengeUI> toUI(List<Challenge> challenges, String environment) {
public String supportedEnvironments() {
return challenge.supportedRuntimeEnvironments().stream().map(environment ->
switch (environment) {
case DOCKER -> "Docker";
case VAULT -> "Kubernetes or Minikube with Vault";
case K8S -> "Kubernetes or Minikube";
case AWS, GCP -> "AWS, GCP";
}
).limit(1).collect(Collectors.joining());
}

public boolean isChallengeEnabled() {
return runtimeEnvironment.environmentIsFitFor(challenge);


// if ("gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
// model.addAttribute("cloud", "enabled");
// }
// if ("k8s-with-vault".equals(k8sEnvironment) || "gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
// model.addAttribute("vault", "enabled");
// }
// if (k8sEnvironment.contains("k8s") || "gcp".equals(k8sEnvironment) || "aws".equals(k8sEnvironment)) {
// model.addAttribute("k8s", "enabled");
// }
}

public static List<ChallengeUI> toUI(List<Challenge> challenges, RuntimeEnvironment environment) {
return challenges.stream().map(challenge -> new ChallengeUI(challenge, challenges.indexOf(challenge) + 1, environment)).toList();
}
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.owasp.wrongsecrets.challenges;

import org.owasp.wrongsecrets.ScoreCard;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
Expand All @@ -14,14 +13,12 @@
@Controller
public class ChallengesController {

private final String version;
private final ScoreCard scoreCard;
private final List<ChallengeUI> challenges;

public ChallengesController(@Value("${APP_VERSION}") String version, @Value("${K8S_ENV}") String k8sEnvironment, ScoreCard scoreCard, List<Challenge> challenges) {
this.version = version;
public ChallengesController(ScoreCard scoreCard, List<ChallengeUI> challenges) {
this.scoreCard = scoreCard;
this.challenges = ChallengeUI.toUI(challenges, k8sEnvironment);
this.challenges = challenges;
}

@GetMapping
Expand All @@ -32,18 +29,15 @@ public String explanation(@PathVariable Integer id) {
@GetMapping("/spoil-{id}")
public String spoiler(Model model, @PathVariable Integer id) {
var challenge = challenges.get(id - 1).getChallenge();
model.addAttribute("challenges", challenges);
model.addAttribute("solution", challenge.spoiler().solution()); //TODO update spoiler class directly instead of the String
model.addAttribute("solution", challenge.spoiler());
return "spoil";
}

@GetMapping("/challenge/{id}")
public String challenge(Model model, @PathVariable Integer id) {
var challenge = challenges.get(id - 1);

model.addAttribute("page", "challenge");
model.addAttribute("challengeForm", new ChallengeForm(""));
model.addAttribute("challenges", challenges);
model.addAttribute("challenge", challenge);

model.addAttribute("answerCorrect", null);
Expand All @@ -53,7 +47,7 @@ public String challenge(Model model, @PathVariable Integer id) {
includeScoringStatus(model, challenge.getChallenge());
addWarning(challenge.getChallenge(), model);

return "index";
return "challenge";
}

@PostMapping("/challenge/{id}")
Expand All @@ -67,14 +61,11 @@ public String postController(@ModelAttribute ChallengeForm challengeForm, Model
}

model.addAttribute("challenge", challenge);
model.addAttribute("challenges", challenges);
model.addAttribute("page", "challenge");
includeScoringStatus(model, challenge.getChallenge());
return "index";
return "challenge";
}

private void includeScoringStatus(Model model, Challenge challenge) {
model.addAttribute("version", version);
model.addAttribute("totalPoints", scoreCard.getTotalReceivedPoints());
model.addAttribute("progress", "" + scoreCard.getProgress());

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@


import lombok.extern.slf4j.Slf4j;
import org.owasp.wrongsecrets.RuntimeEnvironment;
import org.owasp.wrongsecrets.ScoreCard;
import org.owasp.wrongsecrets.challenges.Challenge;
import org.owasp.wrongsecrets.challenges.ChallengeEnvironment;
Expand All @@ -12,6 +13,10 @@

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;

import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.AWS;
import static org.owasp.wrongsecrets.RuntimeEnvironment.Environment.GCP;

@Component
@Order(10)
Expand Down Expand Up @@ -55,4 +60,8 @@ private String getCloudChallenge9and10Value(String filePath, String fileName) {
return awsDefaultValue;
}
}

public List<RuntimeEnvironment.Environment> supportedRuntimeEnvironments() {
return List.of(GCP, AWS);
}
}
Loading

0 comments on commit a3c9797

Please sign in to comment.