Skip to content

Commit

Permalink
Last assignment for JWT tokens finished
Browse files Browse the repository at this point in the history
  • Loading branch information
nbaars committed May 23, 2018
1 parent e06d464 commit dda6f67
Show file tree
Hide file tree
Showing 10 changed files with 394 additions and 45 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,8 @@ define(['jquery',
var prepareDataFunctionName = $(curForm).attr('prepareData');
var callbackFunctionName = $(curForm).attr('callback');
var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize();
var additionalHeadersFunctionName = $(curForm).attr('additionalHeaders');
var additionalHeaders = (typeof webgoat.customjs[additionalHeadersFunctionName] === 'function') ? webgoat.customjs[additionalHeadersFunctionName]() : function() {};
var successCallBackFunctionName = $(curForm).attr('successCallback');
var failureCallbackFunctionName = $(curForm).attr('failureCallback');
var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {};
Expand All @@ -104,6 +106,7 @@ define(['jquery',
$.ajax({
//data:submitData,
url:formUrl,
headers: additionalHeaders,
method:formMethod,
contentType:contentType,
data: submitData,
Expand Down
16 changes: 15 additions & 1 deletion webgoat-container/src/test/resources/logback-test.xml
Original file line number Diff line number Diff line change
@@ -1 +1,15 @@
<configuration />
<configuration />

<!--
Enable below if you want to debug a unit test and see why the controller fails the configuration above is there
to keep the Travis build going otherwise it fails with too much logging.
//TODO we should use a different Spring profile for Travis
-->

<!--
<configuration>
<include resource="org/springframework/boot/logging/logback/base.xml"/>
<logger name="org.springframework.web" level="DEBUG"/>
</configuration>
-->
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
package org.owasp.webgoat.plugin;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import io.jsonwebtoken.*;
import org.apache.commons.lang3.RandomStringUtils;
import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentHints;
import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult;
import org.owasp.webgoat.session.WebSession;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
* @author nbaars
* @since 4/23/17.
*/
@AssignmentPath("/JWT/refresh/")
@AssignmentHints({"jwt-refresh-hint1", "jwt-refresh-hint2", "jwt-refresh-hint3", "jwt-refresh-hint4"})
public class JWTRefreshEndpoint extends AssignmentEndpoint {

public static final String PASSWORD = "bm5nhSkxCXZkKRy4";
private static final String JWT_PASSWORD = "bm5n3SkxCX4kKRy4";
private static final List<String> validRefreshTokens = Lists.newArrayList();

@PostMapping(value = "login", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE)
public @ResponseBody
ResponseEntity follow(@RequestBody Map<String, Object> json) {
String user = (String) json.get("user");
String password = (String) json.get("password");

if ("Jerry".equals(user) && PASSWORD.equals(password)) {
return ResponseEntity.ok(createNewTokens(user));
}
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}

private Map<String, Object> createNewTokens(String user) {
Map<String, Object> claims = Maps.newHashMap();
claims.put("admin", "false");
claims.put("user", user);
String token = Jwts.builder()
.setIssuedAt(new Date(System.currentTimeMillis() + TimeUnit.DAYS.toDays(10)))
.setClaims(claims)
.signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD)
.compact();
Map<String, Object> tokenJson = Maps.newHashMap();
String refreshToken = RandomStringUtils.randomAlphabetic(20);
validRefreshTokens.add(refreshToken);
tokenJson.put("access_token", token);
tokenJson.put("refresh_token", refreshToken);
return tokenJson;
}

@PostMapping("checkout")
public @ResponseBody
AttackResult checkout(@RequestHeader("Authorization") String token) {
try {
Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", ""));
Claims claims = (Claims) jwt.getBody();
String user = (String) claims.get("user");
if ("Tom".equals(user)) {
return trackProgress(success().build());
}
return trackProgress(failed().feedback("jwt-refresh-not-tom").feedbackArgs(user).build());
} catch (ExpiredJwtException e) {
return trackProgress(failed().output(e.getMessage()).build());
} catch (JwtException e) {
return trackProgress(failed().feedback("jwt-invalid-token").build());
}
}

@PostMapping("newToken")
public @ResponseBody
ResponseEntity newToken(@RequestHeader("Authorization") String token, @RequestBody Map<String, Object> json) {
String user;
String refreshToken;
try {
Jwt<Header, Claims> jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(token.replace("Bearer ", ""));
user = (String) jwt.getBody().get("user");
refreshToken = (String) json.get("refresh_token");
} catch (ExpiredJwtException e) {
user = (String) e.getClaims().get("user");
refreshToken = (String) json.get("refresh_token");
}

if (user == null || refreshToken == null) {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
} else if (validRefreshTokens.contains(refreshToken)) {
validRefreshTokens.remove(refreshToken);
return ResponseEntity.ok(createNewTokens(user));
} else {
return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
}
}

}
130 changes: 92 additions & 38 deletions webgoat-lessons/jwt/src/main/resources/html/JWT.html
Original file line number Diff line number Diff line change
Expand Up @@ -110,49 +110,101 @@ <h3>Vote for your favorite</h3>

<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/jwt.css}"/>
<script th:src="@{/lesson_js/bootstrap.min.js}" language="JavaScript"></script>
<script th:src="@{/lesson_js/jwt-final.js}" language="JavaScript"></script>
<script th:src="@{/lesson_js/jwt-refresh.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>
<form class="attack-form" accept-charset="UNKNOWN"
method="POST"
successCallback="jwtSigningCallback"
action="/WebGoat/JWT/refresh/reset"
additionalHeaders="addBearerToken"
action="/WebGoat/JWT/refresh/checkout"
enctype="application/json;charset=UTF-8">
<div class="container-fluid">
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
<div class="card card-inverse card-info">
<img th:src="@{/images/jerry.png}" class="card-img-top"></img>
<div class="card-block">
<figure class="profile profile-inline">
<img th:src="@{/images/jerry.png}" class="profile-avatar" alt=""></img>
</figure>
<h4 class="card-title">Jerry</h4>
<div class="card-text">
Jerry is a small, brown, house mouse.
</div>
</div>
<div class="card-footer">
<small>Last updated 12 minutes ago</small>
<button class="btn btn-info float-right btn-sm">Follow</button>
</div>
</div>
</div>
<div class="col-sm-6 col-md-4 col-lg-3 mt-4">
<div class="card card-inverse card-info">
<img th:src="@{/images/tom.png}" class="card-img-top"></img>
<div class="card-block">
<figure class="profile profile-inline">
<img th:src="@{/images/tom.png}" class="profile-avatar" alt=""></img>
</figure>
<h4 class="card-title">Tom</h4>
<div class="card-text">
Tom is a grey and white domestic short hair cat.
</div>
</div>
<div class="card-footer">
<small>Last updated 12 days ago</small>
<button class="btn btn-info float-right btn-sm">Follow</button>
</div>
<div class="row">
<div class="col-sm-12 col-md-10 col-md-offset-1">
<table class="table table-hover">
<thead>
<tr>
<th>Product</th>
<th>Quantity</th>
<th class="text-center">Price</th>
<th class="text-center">Total</th>
<th> </th>
</tr>
</thead>
<tbody>
<tr>
<td class="col-sm-8 col-md-6">
<div class="media">
<img class="media-object" src="http://icons.iconarchive.com/icons/custom-icon-design/flatastic-2/72/product-icon.png" style="width: 72px; height: 72px;"></img>
<div class="media-body">
<h4 class="media-heading"><a href="#">Learn defending your application with WebGoat</a></h4>
<h5 class="media-heading"> by <a href="#">WebGoat Publishing</a></h5>
<span>Status: </span><span
class="text-success"><strong>In Stock</strong></span>
</div>
</div>
</td>
<td class="col-sm-1 col-md-1" style="text-align: center">
<input type="text" class="form-control" id="quantity1" value="3"></input>
</td>
<td class="col-sm-1 col-md-1 text-center"><strong>$4.87</strong></td>
<td class="col-sm-1 col-md-1 text-center"><strong>$14.61</strong></td>
<td class="col-sm-1 col-md-1">
<button type="button" class="btn btn-danger">
<span class="glyphicon glyphicon-remove"></span> Remove
</button>
</td>
</tr>
<tr>
<td class="col-md-6">
<div class="media">
<img class="media-object" src="http://icons.iconarchive.com/icons/custom-icon-design/flatastic-2/72/product-icon.png" style="width: 72px; height: 72px;"></img>
<div class="media-body">
<h4 class="media-heading"><a href="#">Pentesting for professionals</a></h4>
<h5 class="media-heading"> by <a href="#">WebWolf Publishing</a></h5>
<span>Status: </span><span class="text-warning"><strong>Leaves warehouse in 2 - 3 weeks</strong></span>
</div>
</div>
</td>
<td class="col-md-1" style="text-align: center">
<input type="text" class="form-control" id="quantity2" value="2"></input>
</td>
<td class="col-md-1 text-center"><strong>$4.99</strong></td>
<td class="col-md-1 text-center"><strong>$9.98</strong></td>
<td class="col-md-1">
<button type="button" class="btn btn-danger">
<span class="glyphicon glyphicon-remove"></span> Remove
</button>
</td>
</tr>
</tbody>
<tfoot>
<tr>
<td>  </td>
<td>  </td>
<td>  </td>
<td><h5>Subtotal<br></br>Estimated shipping</h5>
<h3>Total</h3></td>
<td class="text-right"><h5><strong>$24.59<br></br>$6.94</strong></h5>
<h3>$31.53</h3></td>
</tr>
<tr>
<td>  </td>
<td>  </td>
<td>  </td>
<td>
<button type="button" class="btn btn-default">
<span class="glyphicon glyphicon-shopping-cart"></span> Continue Shopping
</button>
</td>
<td>
<button type="submit" class="btn btn-success">
Checkout <span class="glyphicon glyphicon-play"></span>
</button>
</td>
</tr>
</tfoot>
</table>
</div>
</div>
</div>
Expand Down Expand Up @@ -209,7 +261,9 @@ <h4 class="card-title">Tom</h4>
</div>
<div class="card-footer">
<small>Last updated 12 days ago</small>
<button type="button" class="btn btn-info float-right btn-sm" onclick="javascript:follow('Tom')">Follow</button>
<button type="button" class="btn btn-info float-right btn-sm"
onclick="javascript:follow('Tom')">Follow
</button>
<button class="btn btn-info float-right btn-sm">Delete</button>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ jwt-secret-hint1=Save the token and try to verify the token locally
jwt-secret-hint2=Download a word list dictionary (https://github.com/first20hours/google-10000-english)
jwt-secret-hint3=Write a small program or use HashCat for brute forcing the token according the word list

jwt-refresh-hint1=Look at the access log you will find a token there
jwt-refresh-hint2=The token from the access log is no longer valid, can you find a way to refresh it?
jwt-refresh-hint3=The endpoint for refreshing a token is 'jwt/refresh/newToken'
jwt-refresh-hint4=Use the found access token in the Authorization: Bearer header and use your refresh token
jwt-refresh-not-tom=User is not Tom but {0}, please try again

jwt-final-jerry-account=Yikes, you are removing Jerry's account, try to delete the account of Tom
jwt-final-not-tom=Username is not Tom try to pass a token for Tom

Expand Down
10 changes: 5 additions & 5 deletions webgoat-lessons/jwt/src/main/resources/images/logs.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@

205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /statuses/605086114483826688/favorite?authenticity_token=264c8bf11e0212227c001b77543c3519 HTTP/1.1" 404 242 "-" "Go-http-client/1.1" "-"
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /images/phocagallery/almhuette/thumbs/phoca_thumb_l_zimmer.jpg HTTP/1.1" 200 12783 "-" "Go-http-client/1.1" "-"
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /signup HTTP/1.1" 404 212 "-" "Go-http-client/1.1" "-"
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /vsmartseo/status/605086114483826688/actions HTTP/1.1" 404 249 "-" "Go-http-client/1.1" "-"
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /vsmartseo?p=s HTTP/1.1" 404 215 "-" "Go-http-client/1.1" "-"
194.201.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /JWT/refresh/checkout?token=eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q HTTP/1.1" 401 242 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
194.201.170.15 - - [28/Jan/2016:21:28:01 +0100] "POST /JWT/refresh/moveToCheckout HTTP/1.1" 200 12783 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
194.201.170.15 - - [28/Jan/2016:21:28:01 +0100] "POST /JWT/refresh/login HTTP/1.1" 200 212 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
194.201.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /JWT/refresh/addItems HTTP/1.1" 404 249 "-" "Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:60.0) Gecko/20100101 Firefox/60.0" "-"
195.206.170.15 - - [28/Jan/2016:21:28:01 +0100] "POST /JWT/refresh/moveToCheckout HTTP/1.1" 404 215 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.181 Safari/537.36" "-"
42 changes: 42 additions & 0 deletions webgoat-lessons/jwt/src/main/resources/js/jwt-refresh.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
$(document).ready(function () {
login('Jerry');
})

function login(user) {
$.ajax({
type: 'POST',
url: 'JWT/refresh/login',
contentType: "application/json",
data: JSON.stringify({user: user, password: "bm5nhSkxCXZkKRy4"})
}).success(
function (response) {
localStorage.setItem('access_token', response['access_token']);
localStorage.setItem('refresh_token', response['refresh_token']);
}
)
}

//Dev comment: Pass token as header as we had an issue with tokens ending up in the access_log
webgoat.customjs.addBearerToken = function () {
var headers_to_set = {};
headers_to_set['Authorization'] = 'Bearer ' + localStorage.getItem('access_token');
return headers_to_set;
}

//Dev comment: Temporarily disabled from page we need to work out the refresh token flow but for now we can go live with the checkout page
function newToken() {
localStorage.getItem('refreshToken');
$.ajax({
headers: {
'Authorization': 'Bearer ' + localStorage.getItem('access_token')
},
type: 'POST',
url: 'JWT/refresh/newToken',
data: JSON.stringify({refreshToken: localStorage.getItem('refresh_token')})
}).success(
function () {
localStorage.setItem('access_token', apiToken);
localStorage.setItem('refresh_token', refreshToken);
}
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

=== Assignment

Jerry really wants to follow Tom, can you help him to follow Jerry?
From a breach of last year the following logfile is available link:images/logs.txt[here]
Can you find a way to order the books but let *Tom* pay for them?


Loading

0 comments on commit dda6f67

Please sign in to comment.