Finishing challenge 5

This commit is contained in:
Nanne Baars 2017-05-02 19:05:40 +02:00
parent 3cb089d675
commit 262d82f80b
4 changed files with 136 additions and 69 deletions

View File

@ -5,9 +5,12 @@ package org.owasp.webgoat.plugin.challenge5;
* @since 4/30/17. * @since 4/30/17.
*/ */
public class Views { public class Views {
interface GuestView {} interface GuestView {
interface UserView extends GuestView {} }
interface AdminView extends UserView {}
interface UserView extends GuestView {
}
interface AdminView extends UserView {
}
} }

View File

@ -0,0 +1,49 @@
package org.owasp.webgoat.plugin.challenge5;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.Getter;
import lombok.Setter;
/**
* @author nbaars
* @since 5/2/17.
*/
@Getter
public class Vote {
@JsonView(Views.GuestView.class)
private final String title;
@JsonView(Views.GuestView.class)
private final String information;
@JsonView(Views.GuestView.class)
private final String imageSmall;
@JsonView(Views.GuestView.class)
private final String imageBig;
@JsonView(Views.UserView.class)
private int numberOfVotes;
@JsonView(Views.AdminView.class)
@Setter
private String flag;
@JsonView(Views.UserView.class)
private boolean votingAllowed = true;
@JsonView(Views.UserView.class)
private long average = 0;
public Vote(String title, String information, String imageSmall, String imageBig, int numberOfVotes, int totalVotes) {
this.title = title;
this.information = information;
this.imageSmall = imageSmall;
this.imageBig = imageBig;
this.numberOfVotes = numberOfVotes;
this.average = calculateStars(totalVotes);
}
public void incrementNumberOfVotes(int totalVotes) {
this.numberOfVotes = this.numberOfVotes + 1;
this.average = calculateStars(totalVotes);
}
private long calculateStars(int totalVotes) {
return Math.round(((double) numberOfVotes / (double) totalVotes) * 4);
}
}

View File

@ -1,25 +1,27 @@
package org.owasp.webgoat.plugin.challenge5; package org.owasp.webgoat.plugin.challenge5;
import com.fasterxml.jackson.annotation.JsonView;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps; import com.google.common.collect.Maps;
import io.jsonwebtoken.Claims; import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwt; import io.jsonwebtoken.Jwt;
import io.jsonwebtoken.Jwts; import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm; import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Getter;
import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.StringUtils;
import org.springframework.http.HttpStatus; import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.converter.json.MappingJacksonValue; import org.springframework.http.converter.json.MappingJacksonValue;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import javax.annotation.PostConstruct;
import javax.servlet.http.Cookie; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpServletResponse;
import java.util.Collection;
import java.util.Date; import java.util.Date;
import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static java.util.Comparator.comparingLong;
import static java.util.Optional.ofNullable;
import static java.util.stream.Collectors.toList;
import static org.owasp.webgoat.plugin.Flag.FLAGS; import static org.owasp.webgoat.plugin.Flag.FLAGS;
import static org.owasp.webgoat.plugin.SolutionConstants.JWT_PASSWORD; import static org.owasp.webgoat.plugin.SolutionConstants.JWT_PASSWORD;
@ -29,55 +31,31 @@ import static org.owasp.webgoat.plugin.SolutionConstants.JWT_PASSWORD;
*/ */
@RestController @RestController
@RequestMapping("/votings") @RequestMapping("/votings")
public class Votes { public class VotesEndpoint {
private static String validUsers = "TomJerrySylvester"; private static String validUsers = "TomJerrySylvester";
@Getter
private static class Voting {
@JsonView(Views.GuestView.class)
private final String title;
@JsonView(Views.GuestView.class)
private final String information;
@JsonView(Views.GuestView.class)
private final String imageSmall;
@JsonView(Views.GuestView.class)
private final String imageBig;
@JsonView(Views.UserView.class)
private final int numberOfVotes;
@JsonView(Views.AdminView.class)
private String flag = FLAGS.get(5);
@JsonView(Views.UserView.class)
private boolean votingAllowed = true;
@JsonView(Views.UserView.class)
private String average = "0.0";
public Voting(String title, String information, String imageSmall, String imageBig, int numberOfVotes) {
this.title = title;
this.information = information;
this.imageSmall = imageSmall;
this.imageBig = imageBig;
this.numberOfVotes = numberOfVotes;
this.average = String.valueOf((double)numberOfVotes / (double)totalVotes);
}
}
private static int totalVotes = 38929; private static int totalVotes = 38929;
private List votes = Lists.newArrayList( private Map<String, Vote> votes = Maps.newHashMap();
new Voting("Admin lost password",
"In this challenge you will need to help the admin and find the password in order to login", @PostConstruct
"challenge1-small.png", "challenge1.png", 14242), private void initVotes() {
new Voting("Vote for your favourite", votes.put("Admin lost password", new Vote("Admin lost password",
"In this challenge ...", "In this challenge you will need to help the admin and find the password in order to login",
"challenge5-small.png", "challenge5.png", 12345), "challenge1-small.png", "challenge1.png", 36000, totalVotes));
new Voting("Get is for free", votes.put("Vote for your favourite",
"The objective for this challenge is to buy a Samsung phone for free.", new Vote("Vote for your favourite",
"challenge2-small.png", "challenge2.png", 12342), "In this challenge ...",
new Voting("Photo comments", "challenge5-small.png", "challenge5.png", 30000, totalVotes));
"n this challenge you can comment on the photo you will need to find the flag somewhere.", votes.put("Get it for free",
"challenge3-small.png", "challenge3.png", 12342) new Vote("Get it for free",
); "The objective for this challenge is to buy a Samsung phone for free.",
"challenge2-small.png", "challenge2.png", 20000, totalVotes));
votes.put("Photo comments",
new Vote("Photo comments",
"n this challenge you can comment on the photo you will need to find the flag somewhere.",
"challenge3-small.png", "challenge3.png", 10000, totalVotes));
}
@GetMapping("/login") @GetMapping("/login")
public void login(@RequestParam("user") String user, HttpServletResponse response) { public void login(@RequestParam("user") String user, HttpServletResponse response) {
@ -102,18 +80,19 @@ public class Votes {
@GetMapping @GetMapping
public MappingJacksonValue getVotes(@CookieValue(value = "access_token", required = false) String accessToken) { public MappingJacksonValue getVotes(@CookieValue(value = "access_token", required = false) String accessToken) {
MappingJacksonValue value = new MappingJacksonValue(votes); MappingJacksonValue value = new MappingJacksonValue(votes.values().stream().sorted(comparingLong(Vote::getAverage).reversed()).collect(toList()));
if (StringUtils.isEmpty(accessToken)) { if (StringUtils.isEmpty(accessToken)) {
value.setSerializationView(Views.GuestView.class); value.setSerializationView(Views.GuestView.class);
} else { } else {
try { try {
Jwt jwt = Jwts.parser().parse(accessToken); Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
Claims claims = (Claims) jwt.getBody(); Claims claims = (Claims) jwt.getBody();
String user = (String) claims.get("user"); String user = (String) claims.get("user");
boolean isAdmin = Boolean.valueOf((String) claims.get("admin")); boolean isAdmin = Boolean.valueOf((String) claims.get("admin"));
if ("Guest".equals(user)) { if ("Guest".equals(user)) {
value.setSerializationView(Views.GuestView.class); value.setSerializationView(Views.GuestView.class);
} else { } else {
((Collection<Vote>)value.getValue()).forEach(v -> v.setFlag(FLAGS.get(5)));
value.setSerializationView(isAdmin ? Views.AdminView.class : Views.UserView.class); value.setSerializationView(isAdmin ? Views.AdminView.class : Views.UserView.class);
} }
} catch (IllegalArgumentException e) { } catch (IllegalArgumentException e) {
@ -123,11 +102,22 @@ public class Votes {
return value; return value;
} }
@PostMapping @PostMapping(value = "{title}")
@ResponseBody @ResponseBody
@ResponseStatus(HttpStatus.ACCEPTED) @ResponseStatus(HttpStatus.ACCEPTED)
public void vote(String title) { public ResponseEntity<?> vote(@PathVariable String title, @CookieValue(value = "access_token", required = false) String accessToken) {
totalVotes = totalVotes + 1; if (StringUtils.isEmpty(accessToken)) {
//return return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
} else {
Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
Claims claims = (Claims) jwt.getBody();
String user = (String) claims.get("user");
if (validUsers.contains(user)) {
ofNullable(votes.get(title)).ifPresent(v -> v.incrementNumberOfVotes(totalVotes));
return ResponseEntity.accepted().build();
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}
} }
} }

View File

@ -1,13 +1,15 @@
$(document).ready(function () { $(document).ready(function () {
getVotings();
login('Guest'); login('Guest');
}) })
function login(user) { function login(user) {
$("#name").text(user); $("#name").text(user);
$.get("votings/login?user=" + user, function (result, status) { $.ajax({
url: "votings/login?user=" + user,
complete: function (result, status) {
getVotings();
}
}); });
getVotings();
} }
var html = '<a href="#" class="list-group-item ACTIVE">' + var html = '<a href="#" class="list-group-item ACTIVE">' +
@ -21,17 +23,17 @@ var html = '<a href="#" class="list-group-item ACTIVE">' +
'<p class="list-group-item-text">INFORMATION</p>' + '<p class="list-group-item-text">INFORMATION</p>' +
'</div>' + '</div>' +
'<div class="col-md-3 text-center">' + '<div class="col-md-3 text-center">' +
'<h2>NO_VOTES' + '<h2 HIDDEN_VIEW_VOTES>NO_VOTES' +
'<small> votes</small>' + '<small HIDDEN_VIEW_VOTES> votes</small>' +
'</h2>' + '</h2>' +
'<button type="button" class="btn BUTTON btn-lg btn-block">Vote Now!</button>' + '<button type="button" id="TITLE" class="btn BUTTON btn-lg btn-block" onclick="vote(this.id)">Vote Now!</button>' +
'<div class="stars"> ' + '<div style="visibility:HIDDEN_VIEW_RATING;" class="stars"> ' +
'<span class="glyphicon glyphicon-star"></span>' + '<span class="glyphicon glyphicon-star"></span>' +
'<span class="glyphicon glyphicon-star"></span>' + '<span class="glyphicon glyphicon-star"></span>' +
'<span class="glyphicon glyphicon-star"></span>' + '<span class="glyphicon glyphicon-star"></span>' +
'<span class="glyphicon glyphicon-star-empty"></span>' + '<span class="glyphicon glyphicon-star-empty"></span>' +
'</div>' + '</div>' +
'<p>Average AVERAGE<small> /</small>4</p>' + '<p HIDDEN_VIEW_RATING>Average AVERAGE<small> /</small>4</p>' +
'</div>' + '</div>' +
'<div class="clearfix"></div>' + '<div class="clearfix"></div>' +
'</a>'; '</a>';
@ -41,19 +43,42 @@ function getVotings() {
$.get("votings/", function (result, status) { $.get("votings/", function (result, status) {
for (var i = 0; i < result.length; i++) { for (var i = 0; i < result.length; i++) {
var voteTemplate = html.replace('IMAGE_SMALL', result[i].imageSmall); var voteTemplate = html.replace('IMAGE_SMALL', result[i].imageSmall);
if ( i === 0 ) { if (i === 0) {
voteTemplate = voteTemplate.replace('ACTIVE', 'active'); voteTemplate = voteTemplate.replace('ACTIVE', 'active');
voteTemplate = voteTemplate.replace('BUTTON', 'btn-default'); voteTemplate = voteTemplate.replace('BUTTON', 'btn-default');
} else { } else {
voteTemplate = voteTemplate.replace('ACTIVE', ''); voteTemplate = voteTemplate.replace('ACTIVE', '');
voteTemplate = voteTemplate.replace('BUTTON', 'btn-primary'); voteTemplate = voteTemplate.replace('BUTTON', 'btn-primary');
} }
voteTemplate = voteTemplate.replace(/TITLE/g, result[i].title);
voteTemplate = voteTemplate.replace('TITLE', result[i].title);
voteTemplate = voteTemplate.replace('INFORMATION', result[i].information || ''); voteTemplate = voteTemplate.replace('INFORMATION', result[i].information || '');
voteTemplate = voteTemplate.replace('NO_VOTES', result[i].numberOfVotes || ''); voteTemplate = voteTemplate.replace('NO_VOTES', result[i].numberOfVotes || '');
voteTemplate = voteTemplate.replace('AVERAGE', result[i].average || '');
var hidden = (result[i].numberOfVotes === undefined ? 'hidden' : '');
voteTemplate = voteTemplate.replace(/HIDDEN_VIEW_VOTES/g, hidden);
hidden = (result[i].average === undefined ? 'hidden' : '');
voteTemplate = voteTemplate.replace(/HIDDEN_VIEW_RATING/g, hidden);
$("#votesList").append(voteTemplate); $("#votesList").append(voteTemplate);
} }
}) })
} }
function vote(title) {
var user = $("#name").text();
if (user === 'Guest') {
alert("As a guest you are not allowed to vote, please login first.")
} else {
$.ajax({
type: 'POST',
url: 'votings/' + title
}).then(
function () {
getVotings();
}
)
}
}