Moved challenge2 to client-side-filtering as final assignment
This commit is contained in:
@ -10,7 +10,6 @@ public interface SolutionConstants {
|
||||
|
||||
//TODO should be random generated when starting the server
|
||||
String PASSWORD = "!!webgoat_admin_1234!!";
|
||||
String SUPER_COUPON_CODE = "get_it_for_free";
|
||||
String PASSWORD_TOM = "thisisasecretfortomonly";
|
||||
String PASSWORD_LARRY = "larryknows";
|
||||
String JWT_PASSWORD = "victory";
|
||||
|
@ -1,32 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpoint;
|
||||
import org.owasp.webgoat.assignments.AssignmentPath;
|
||||
import org.owasp.webgoat.assignments.AttackResult;
|
||||
import org.owasp.webgoat.plugin.Flag;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/6/17.
|
||||
*/
|
||||
@AssignmentPath("/challenge/2")
|
||||
public class Assignment2 extends AssignmentEndpoint {
|
||||
|
||||
@RequestMapping(method = RequestMethod.POST)
|
||||
public
|
||||
@ResponseBody
|
||||
AttackResult completed(@RequestParam String checkoutCode) throws IOException {
|
||||
if (SUPER_COUPON_CODE.equals(checkoutCode)) {
|
||||
return success().feedback("challenge.solved").feedbackArgs(Flag.FLAGS.get(2)).build();
|
||||
}
|
||||
return failed().build();
|
||||
}
|
||||
}
|
@ -1,39 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
|
||||
import com.google.common.collect.Lists;
|
||||
import org.owasp.webgoat.lessons.Category;
|
||||
import org.owasp.webgoat.lessons.NewLesson;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 3/21/17.
|
||||
*/
|
||||
public class Challenge2 extends NewLesson {
|
||||
|
||||
@Override
|
||||
public Category getDefaultCategory() {
|
||||
return Category.CHALLENGE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getHints() {
|
||||
return Lists.newArrayList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Integer getDefaultRanking() {
|
||||
return 10;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return "challenge2.title";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getId() {
|
||||
return "Challenge2";
|
||||
}
|
||||
}
|
@ -1,68 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
|
||||
import com.beust.jcommander.internal.Lists;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 4/6/17.
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("challenge-store")
|
||||
public class ShopEndpoint {
|
||||
|
||||
@AllArgsConstructor
|
||||
private class CheckoutCodes {
|
||||
|
||||
@Getter
|
||||
private List<CheckoutCode> codes = Lists.newArrayList();
|
||||
|
||||
public Optional<CheckoutCode> get(String code) {
|
||||
return codes.stream().filter(c -> c.getCode().equals(code)).findFirst();
|
||||
}
|
||||
}
|
||||
|
||||
@AllArgsConstructor
|
||||
@Getter
|
||||
private class CheckoutCode {
|
||||
private String code;
|
||||
private int discount;
|
||||
}
|
||||
|
||||
private CheckoutCodes checkoutCodes;
|
||||
|
||||
public ShopEndpoint() {
|
||||
List<CheckoutCode> codes = Lists.newArrayList();
|
||||
codes.add(new CheckoutCode("webgoat", 25));
|
||||
codes.add(new CheckoutCode("owasp", 25));
|
||||
codes.add(new CheckoutCode("owasp-webgoat", 50));
|
||||
this.checkoutCodes = new CheckoutCodes(codes);
|
||||
}
|
||||
|
||||
@GetMapping(value = "/coupons/{code}", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public CheckoutCode getDiscountCode(@PathVariable String code) {
|
||||
if (SUPER_COUPON_CODE.equals(code)) {
|
||||
return new CheckoutCode(SUPER_COUPON_CODE, 100);
|
||||
}
|
||||
return checkoutCodes.get(code).orElse(new CheckoutCode("no", 0));
|
||||
}
|
||||
|
||||
@GetMapping(value = "/coupons", produces = MediaType.APPLICATION_JSON_VALUE)
|
||||
public CheckoutCodes all() {
|
||||
List<CheckoutCode> all = Lists.newArrayList();
|
||||
all.addAll(this.checkoutCodes.getCodes());
|
||||
all.add(new CheckoutCode(SUPER_COUPON_CODE, 100));
|
||||
return new CheckoutCodes(all);
|
||||
}
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
ul > li{margin-right:25px;font-weight:lighter;cursor:pointer}
|
||||
li.active{border-bottom:3px solid silver;}
|
||||
|
||||
.item-photo{display:flex;justify-content:center;align-items:center;border-right:1px solid #f6f6f6;}
|
||||
.menu-items{list-style-type:none;font-size:11px;display:inline-flex;margin-bottom:0px;margin-top:20px}
|
||||
.btn-success{width:100%;border-radius:0px;}
|
||||
.section{width:100%;margin-left:-15px;padding:2px;padding-left:15px;padding-right:15px;background:#f8f9f9}
|
||||
.title-price{margin-top:30px;margin-bottom:0px;color:black}
|
||||
.title-attr{margin-top:0px;margin-bottom:0px;color:black;}
|
||||
.btn-minus{cursor:pointer;font-size:7px;display:flex;align-items:center;padding:5px;padding-left:10px;padding-right:10px;border:1px solid gray;border-radius:2px;border-right:0px;}
|
||||
.btn-plus{cursor:pointer;font-size:7px;display:flex;align-items:center;padding:5px;padding-left:10px;padding-right:10px;border:1px solid gray;border-radius:2px;border-left:0px;}
|
||||
div.section > div {width:100%;display:inline-flex;}
|
||||
div.section > div > input {margin:0px;padding-left:5px;font-size:10px;padding-right:5px;max-width:18%;text-align:center;}
|
||||
.attr,.attr2{cursor:pointer;margin-right:5px;height:20px;font-size:11px;padding:2px;border:1px solid gray;border-radius:2px;}
|
||||
.attr.active,.attr2.active{ border:2px solid orange;}
|
||||
|
||||
@media (max-width: 426px) {
|
||||
.container {margin-top:0px !important;}
|
||||
.container > .row{padding:0px !important;}
|
||||
.container > .row > .col-xs-12.col-sm-5{
|
||||
padding-right:0px ;
|
||||
}
|
||||
.container > .row > .col-xs-12.col-sm-9 > div > p{
|
||||
padding-left:0px !important;
|
||||
padding-right:0px !important;
|
||||
}
|
||||
.container > .row > .col-xs-12.col-sm-9 > div > ul{
|
||||
padding-left:10px !important;
|
||||
|
||||
}
|
||||
.section{width:104%;}
|
||||
.menu-items{padding-left:0px;}
|
||||
}
|
@ -1,112 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
|
||||
<html xmlns:th="http://www.thymeleaf.org">
|
||||
|
||||
|
||||
<div class="lesson-page-wrapper">
|
||||
<div class="adoc-content" th:replace="doc:Challenge_2.adoc"></div>
|
||||
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/challenge2.css}"/>
|
||||
<script th:src="@{/lesson_js/challenge2.js}" language="JavaScript"></script>
|
||||
<div class="attack-container">
|
||||
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
|
||||
|
||||
<div class="container-fluid">
|
||||
<form class="attack-form" accept-charset="UNKNOWN"
|
||||
method="POST" name="form"
|
||||
action="/WebGoat/challenge/2"
|
||||
enctype="application/json;charset=UTF-8">
|
||||
|
||||
<input id="discount" type="hidden" value="0"/>
|
||||
<div class="row">
|
||||
|
||||
<div class="col-xs-3 item-photo">
|
||||
<img style="max-width:100%;" th:src="@{/images/samsung-black.jpg}"/>
|
||||
</div>
|
||||
<div class="col-xs-5" style="border:0px solid gray">
|
||||
<h3>Samsung Galaxy S8</h3>
|
||||
<h5 style="color:#337ab7"><a href="http://www.samsung.com">Samsung</a> ·
|
||||
<small style="color:#337ab7">(124421 reviews)</small>
|
||||
</h5>
|
||||
|
||||
<h6 class="title-price">
|
||||
<small>PRICE</small>
|
||||
</h6>
|
||||
<h3 style="margin-top:0px;"><span>US $</span><span id="price">899</span></h3>
|
||||
|
||||
<div class="section">
|
||||
<h6 class="title-attr" style="margin-top:15px;">
|
||||
<small>COLOR</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="attr" style="width:25px;background:lightgrey;"></div>
|
||||
<div class="attr" style="width:25px;background:black;"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>CAPACITY</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="attr2">64 GB</div>
|
||||
<div class="attr2">128 GB</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>QUANTITY</small>
|
||||
</h6>
|
||||
<div>
|
||||
<div class="btn-minus"><span class="glyphicon glyphicon-minus"></span></div>
|
||||
<input class="quantity" value="1"/>
|
||||
<div class="btn-plus"><span class="glyphicon glyphicon-plus"></span></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="section" style="padding-bottom:5px;">
|
||||
<h6 class="title-attr">
|
||||
<small>CHECKOUT CODE</small>
|
||||
</h6>
|
||||
<!--
|
||||
Checkout code: webgoat, owasp, owasp-webgoat
|
||||
-->
|
||||
<input name="checkoutCode" class="checkoutCode" value=""/>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="section" style="padding-bottom:20px;">
|
||||
<button type="submit" class="btn btn-success"><span style="margin-right:20px"
|
||||
class="glyphicon glyphicon-shopping-cart"
|
||||
aria-hidden="true"></span>Buy
|
||||
</button>
|
||||
<h6><a href="#"><span class="glyphicon glyphicon-heart-empty"
|
||||
style="cursor:pointer;"></span>
|
||||
Like</a></h6>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
<br/>
|
||||
<form class="attack-form" method="POST" name="form" action="/WebGoat/challenge/flag">
|
||||
<div class="form-group">
|
||||
<div class="input-group">
|
||||
<div class="input-group-addon"><i class="fa fa-flag-checkered" aria-hidden="true"
|
||||
style="font-size:20px"></i></div>
|
||||
<input type="text" class="form-control" id="flag" name="flag"
|
||||
placeholder="a7179f89-906b-4fec-9d99-f15b796e7208"/>
|
||||
</div>
|
||||
<div class="input-group" style="margin-top: 10px">
|
||||
<button type="submit" class="btn btn-primary">Submit flag</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
<br/>
|
||||
<div class="attack-feedback"></div>
|
||||
<div class="attack-output"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</html>
|
Binary file not shown.
Before Width: | Height: | Size: 12 KiB |
Binary file not shown.
Before Width: | Height: | Size: 11 KiB |
@ -1,64 +0,0 @@
|
||||
$(document).ready(function () {
|
||||
//-- Click on detail
|
||||
$("ul.menu-items > li").on("click", function () {
|
||||
$("ul.menu-items > li").removeClass("active");
|
||||
$(this).addClass("active");
|
||||
})
|
||||
|
||||
$(".attr,.attr2").on("click", function () {
|
||||
var clase = $(this).attr("class");
|
||||
|
||||
$("." + clase).removeClass("active");
|
||||
$(this).addClass("active");
|
||||
})
|
||||
|
||||
//-- Click on QUANTITY
|
||||
$(".btn-minus").on("click", function () {
|
||||
var now = $(".quantity").val();
|
||||
if ($.isNumeric(now)) {
|
||||
if (parseInt(now) - 1 > 0) {
|
||||
now--;
|
||||
}
|
||||
$(".quantity").val(now);
|
||||
$('#price').text(now * 899);
|
||||
} else {
|
||||
$(".quantity").val("1");
|
||||
$('#price').text(899);
|
||||
}
|
||||
calculate();
|
||||
})
|
||||
$(".btn-plus").on("click", function () {
|
||||
var now = $(".quantity").val();
|
||||
if ($.isNumeric(now)) {
|
||||
$(".quantity").val(parseInt(now) + 1);
|
||||
} else {
|
||||
$(".quantity").val("1");
|
||||
}
|
||||
calculate();
|
||||
})
|
||||
$(".checkoutCode").on("blur", function () {
|
||||
var checkoutCode = $(".checkoutCode").val();
|
||||
$.get("challenge-store/coupons/" + checkoutCode, function (result, status) {
|
||||
var discount = result.discount;
|
||||
if (discount > 0) {
|
||||
$('#discount').text(discount);
|
||||
calculate();
|
||||
} else {
|
||||
$('#discount').text(0);
|
||||
calculate();
|
||||
}
|
||||
});
|
||||
})
|
||||
|
||||
function calculate() {
|
||||
var d = $('#discount').text();
|
||||
var price = $('#price').val();
|
||||
var quantity = parseInt($(".quantity").val());
|
||||
if (d > 0) {
|
||||
$('#price').text((quantity * (899 - (899 * d / 100))).toFixed(2));
|
||||
|
||||
} else {
|
||||
$('#price').text(quantity * 899);
|
||||
}
|
||||
}
|
||||
})
|
@ -1 +0,0 @@
|
||||
No need to pay if you know the code ...
|
@ -1,49 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.owasp.webgoat.assignments.AssignmentEndpointTest;
|
||||
import org.owasp.webgoat.plugin.Flag;
|
||||
import org.owasp.webgoat.plugin.SolutionConstants;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/2/17.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class Assignment2Test extends AssignmentEndpointTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
Assignment2 assignment2 = new Assignment2();
|
||||
init(assignment2);
|
||||
new Flag().initFlags();
|
||||
this.mockMvc = standaloneSetup(assignment2).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void success() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/challenge/2")
|
||||
.param("checkoutCode", SolutionConstants.SUPER_COUPON_CODE))
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.containsString("flag: " + Flag.FLAGS.get(2))))
|
||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void wrongCouponCode() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.post("/challenge/2")
|
||||
.param("checkoutCode", "test"))
|
||||
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.not.solved"))))
|
||||
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
|
||||
}
|
||||
}
|
@ -1,58 +0,0 @@
|
||||
package org.owasp.webgoat.plugin.challenge2;
|
||||
|
||||
import org.hamcrest.CoreMatchers;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.mockito.runners.MockitoJUnitRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
|
||||
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.owasp.webgoat.plugin.SolutionConstants.SUPER_COUPON_CODE;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup;
|
||||
|
||||
/**
|
||||
* @author nbaars
|
||||
* @since 5/2/17.
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class ShopEndpointTest {
|
||||
|
||||
private MockMvc mockMvc;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
ShopEndpoint shopEndpoint = new ShopEndpoint();
|
||||
this.mockMvc = standaloneSetup(shopEndpoint).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getSuperCoupon() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/" + SUPER_COUPON_CODE))
|
||||
.andExpect(jsonPath("$.code", CoreMatchers.is(SUPER_COUPON_CODE)))
|
||||
.andExpect(jsonPath("$.discount", CoreMatchers.is(100)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void getCoupon() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/webgoat"))
|
||||
.andExpect(jsonPath("$.code", CoreMatchers.is("webgoat")))
|
||||
.andExpect(jsonPath("$.discount", CoreMatchers.is(25)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void askForUnknownCouponCode() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/does-not-exists"))
|
||||
.andExpect(jsonPath("$.code", CoreMatchers.is("no")))
|
||||
.andExpect(jsonPath("$.discount", CoreMatchers.is(0)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void fetchAllTheCouponsShouldContainGetItForFree() throws Exception {
|
||||
mockMvc.perform(MockMvcRequestBuilders.get("/challenge-store/coupons/"))
|
||||
.andExpect(jsonPath("$.codes[3].code", is("get_it_for_free")));
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user