Last assignment for JWT tokens finished

This commit is contained in:
Nanne Baars 2018-05-22 17:06:03 +02:00
parent e06d4642eb
commit dda6f674a3
10 changed files with 394 additions and 45 deletions

View File

@ -90,6 +90,8 @@ define(['jquery',
var prepareDataFunctionName = $(curForm).attr('prepareData'); var prepareDataFunctionName = $(curForm).attr('prepareData');
var callbackFunctionName = $(curForm).attr('callback'); var callbackFunctionName = $(curForm).attr('callback');
var submitData = (typeof webgoat.customjs[prepareDataFunctionName] === 'function') ? webgoat.customjs[prepareDataFunctionName]() : $(curForm).serialize(); 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 successCallBackFunctionName = $(curForm).attr('successCallback');
var failureCallbackFunctionName = $(curForm).attr('failureCallback'); var failureCallbackFunctionName = $(curForm).attr('failureCallback');
var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {}; var callbackFunction = (typeof webgoat.customjs[callbackFunctionName] === 'function') ? webgoat.customjs[callbackFunctionName] : function() {};
@ -104,6 +106,7 @@ define(['jquery',
$.ajax({ $.ajax({
//data:submitData, //data:submitData,
url:formUrl, url:formUrl,
headers: additionalHeaders,
method:formMethod, method:formMethod,
contentType:contentType, contentType:contentType,
data: submitData, data: submitData,

View File

@ -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>
-->

View File

@ -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();
}
}
}

View File

@ -110,49 +110,101 @@
<link rel="stylesheet" type="text/css" th:href="@{/lesson_css/jwt.css}"/> <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/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="attack-container">
<div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div> <div class="assignment-success"><i class="fa fa-2 fa-check hidden" aria-hidden="true"></i></div>
<form class="attack-form" accept-charset="UNKNOWN" <form class="attack-form" accept-charset="UNKNOWN"
method="POST" method="POST"
successCallback="jwtSigningCallback" additionalHeaders="addBearerToken"
action="/WebGoat/JWT/refresh/reset" action="/WebGoat/JWT/refresh/checkout"
enctype="application/json;charset=UTF-8"> enctype="application/json;charset=UTF-8">
<div class="container-fluid"> <div class="container-fluid">
<div class="col-sm-6 col-md-4 col-lg-3 mt-4"> <div class="row">
<div class="card card-inverse card-info"> <div class="col-sm-12 col-md-10 col-md-offset-1">
<img th:src="@{/images/jerry.png}" class="card-img-top"></img> <table class="table table-hover">
<div class="card-block"> <thead>
<figure class="profile profile-inline"> <tr>
<img th:src="@{/images/jerry.png}" class="profile-avatar" alt=""></img> <th>Product</th>
</figure> <th>Quantity</th>
<h4 class="card-title">Jerry</h4> <th class="text-center">Price</th>
<div class="card-text"> <th class="text-center">Total</th>
Jerry is a small, brown, house mouse. <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>
</div> </div>
<div class="card-footer"> </td>
<small>Last updated 12 minutes ago</small> <td class="col-sm-1 col-md-1" style="text-align: center">
<button class="btn btn-info float-right btn-sm">Follow</button> <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>
</div> </div>
</div> </td>
<div class="col-sm-6 col-md-4 col-lg-3 mt-4"> <td class="col-md-1" style="text-align: center">
<div class="card card-inverse card-info"> <input type="text" class="form-control" id="quantity2" value="2"></input>
<img th:src="@{/images/tom.png}" class="card-img-top"></img> </td>
<div class="card-block"> <td class="col-md-1 text-center"><strong>$4.99</strong></td>
<figure class="profile profile-inline"> <td class="col-md-1 text-center"><strong>$9.98</strong></td>
<img th:src="@{/images/tom.png}" class="profile-avatar" alt=""></img> <td class="col-md-1">
</figure> <button type="button" class="btn btn-danger">
<h4 class="card-title">Tom</h4> <span class="glyphicon glyphicon-remove"></span> Remove
<div class="card-text"> </button>
Tom is a grey and white domestic short hair cat. </td>
</div> </tr>
</div> </tbody>
<div class="card-footer"> <tfoot>
<small>Last updated 12 days ago</small> <tr>
<button class="btn btn-info float-right btn-sm">Follow</button> <td>  </td>
</div> <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> </div>
</div> </div>
@ -209,7 +261,9 @@
</div> </div>
<div class="card-footer"> <div class="card-footer">
<small>Last updated 12 days ago</small> <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> <button class="btn btn-info float-right btn-sm">Delete</button>
</div> </div>
</div> </div>

View File

@ -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-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-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-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 jwt-final-not-tom=Username is not Tom try to pass a token for Tom

View File

@ -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" "-" 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" "-"
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" "-" 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" "-"
205.167.170.15 - - [28/Jan/2016:21:28:01 +0100] "GET /signup HTTP/1.1" 404 212 "-" "Go-http-client/1.1" "-" 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" "-"
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" "-" 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" "-"
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" "-" 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" "-"

View File

@ -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);
}
)
}

View File

@ -2,7 +2,7 @@
=== Assignment === 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] 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?

View File

@ -0,0 +1,102 @@
package org.owasp.webgoat.plugin;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.Maps;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import java.util.Map;
import static org.hamcrest.Matchers.is;
import static org.mockito.Mockito.when;
import static org.owasp.webgoat.plugin.JWTRefreshEndpoint.PASSWORD;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@RunWith(SpringJUnit4ClassRunner.class)
public class JWTRefreshEndpointTest extends LessonTest {
@Before
public void setup() {
JWT jwt = new JWT();
when(webSession.getCurrentLesson()).thenReturn(jwt);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void solveAssignment() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
//First login to obtain tokens for Jerry
Map<String, Object> loginJson = Maps.newHashMap();
loginJson.put("user", "Jerry");
loginJson.put("password", PASSWORD);
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginJson)))
.andExpect(status().isOk())
.andReturn();
Map<String, String> tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class);
String accessToken = tokens.get("access_token");
String refreshToken = tokens.get("refresh_token");
//Now create a new refresh token for Tom based on Toms old access token and send the refresh token of Jerry
String accessTokenTom = "eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q";
Map<String, Object> refreshJson = Maps.newHashMap();
refreshJson.put("refresh_token", refreshToken);
result = mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/newToken")
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + accessTokenTom)
.content(objectMapper.writeValueAsString(refreshJson)))
.andExpect(status().isOk())
.andReturn();
tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class);
accessTokenTom = tokens.get("access_token");
//Now checkout with the new token from Tom
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout")
.header("Authorization", "Bearer " + accessTokenTom))
.andExpect(status().isOk())
.andExpect(jsonPath("$.lessonCompleted", is(true)));
}
@Test
public void checkoutWithTomsTokenFromAccessLogShouldFail() throws Exception {
String accessTokenTom = "eyJhbGciOiJIUzUxMiJ9.eyJpYXQiOjE1MjYxMzE0MTEsImV4cCI6MTUyNjIxNzgxMSwiYWRtaW4iOiJmYWxzZSIsInVzZXIiOiJUb20ifQ.DCoaq9zQkyDH25EcVWKcdbyVfUL4c9D4jRvsqOqvi9iAd4QuqmKcchfbU8FNzeBNF9tLeFXHZLU4yRkq-bjm7Q";
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout")
.header("Authorization", "Bearer " + accessTokenTom))
.andExpect(status().isOk())
.andExpect(jsonPath("$.output", CoreMatchers.containsString("JWT expired at")));
}
@Test
public void flowForJerryAlwaysWorks() throws Exception {
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> loginJson = Maps.newHashMap();
loginJson.put("user", "Jerry");
loginJson.put("password", PASSWORD);
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/login")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(loginJson)))
.andExpect(status().isOk())
.andReturn();
Map<String, String> tokens = objectMapper.readValue(result.getResponse().getContentAsString(), Map.class);
String accessToken = tokens.get("access_token");
mockMvc.perform(MockMvcRequestBuilders.post("/JWT/refresh/checkout")
.header("Authorization", "Bearer " + accessToken))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", is("User is not Tom but Jerry, please try again")));
}
}

View File

@ -6,6 +6,10 @@ import io.jsonwebtoken.*;
import io.jsonwebtoken.impl.TextCodec; import io.jsonwebtoken.impl.TextCodec;
import org.junit.Test; import org.junit.Test;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.Period;
import java.util.Date; import java.util.Date;
import java.util.Map; import java.util.Map;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -34,4 +38,19 @@ public class TokenTest {
}).parse(token); }).parse(token);
} }
@Test
public void testRefresh() {
Instant now = Instant.now(); //current date
Claims claims = Jwts.claims().setIssuedAt(Date.from(now.minus(Duration.ofDays(10))));
claims.setExpiration(Date.from(now.minus(Duration.ofDays(9))));
claims.put("admin", "false");
claims.put("user", "Tom");
String token = Jwts.builder().setClaims(claims)
.signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, "bm5n3SkxCX4kKRy4")
.compact();
//Jws<Claims> jws = Jwts.parser().setSigningKey("bm5n3SkxCX4kKRy4").parseClaimsJws(token);
//Jwts.parser().setSigningKey().parsePlaintextJws(token);
System.out.println(token);
}
} }