From 8d7ecb19d79ee614a90d4567c200a41533febdc1 Mon Sep 17 00:00:00 2001
From: Nanne Baars <nanne.baars@owasp.org>
Date: Wed, 23 May 2018 12:51:57 +0200
Subject: [PATCH] Added testcases for all JWT endpoints

---
 .../webgoat/plugin/JWTSecretKeyEndpoint.java  |  31 ++-
 .../webgoat/plugin/JWTVotesEndpoint.java      |  14 +-
 .../plugin/refresh/RefreshEndpoint.java       |   9 -
 .../org/owasp/webgoat/plugin/votes/Views.java |   3 -
 .../org/owasp/webgoat/plugin/votes/Vote.java  |   3 -
 .../resources/i18n/WebGoatLabels.properties   |   4 +-
 .../plugin/JWTSecretKeyEndpointTest.java      | 110 +++++++++++
 .../webgoat/plugin/JWTVotesEndpointTest.java  | 187 ++++++++++++++++++
 8 files changed, 329 insertions(+), 32 deletions(-)
 delete mode 100644 webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/refresh/RefreshEndpoint.java
 create mode 100644 webgoat-lessons/jwt/src/test/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpointTest.java
 create mode 100644 webgoat-lessons/jwt/src/test/java/org/owasp/webgoat/plugin/JWTVotesEndpointTest.java

diff --git a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java
index 1ce27e416..5748681f5 100644
--- a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java
+++ b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpoint.java
@@ -1,14 +1,19 @@
 package org.owasp.webgoat.plugin;
 
+import com.google.common.collect.Lists;
 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.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestParam;
 
 import io.jsonwebtoken.Claims;
 import io.jsonwebtoken.Jwt;
 import io.jsonwebtoken.Jwts;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.util.List;
 
 /**
  * @author nbaars
@@ -18,23 +23,29 @@ import io.jsonwebtoken.Jwts;
 @AssignmentHints({"jwt-secret-hint1", "jwt-secret-hint2", "jwt-secret-hint3"})
 public class JWTSecretKeyEndpoint extends AssignmentEndpoint {
 
-    private static final String JWT_SECRET = "victory";
+    public static final String JWT_SECRET = "victory";
     private static final String WEBGOAT_USER = "WebGoat";
+    private static final List<String> expectedClaims = Lists.newArrayList("iss", "iat", "exp", "aud", "sub", "username", "Email", "Role");
 
-    @PostMapping()
-    public void login(@RequestParam String token) {
+    @PostMapping
+    @ResponseBody
+    public AttackResult login(@RequestParam String token) {
         try {
-            Jwt jwt = Jwts.parser().setSigningKey(JWT_SECRET).parseClaimsJwt(token);
+            Jwt jwt = Jwts.parser().setSigningKey(JWT_SECRET).parse(token);
             Claims claims = (Claims) jwt.getBody();
-            String user = (String) claims.get("username");
-
-            if (WEBGOAT_USER.equalsIgnoreCase(user)) {
-                trackProgress(success().build());
+            if (!claims.keySet().containsAll(expectedClaims)) {
+                return trackProgress(failed().feedback("jwt-secret-claims-missing").build());
             } else {
-                trackProgress(failed().feedback("jwt-secret.not-correct").feedbackArgs(user).build());
+                String user = (String) claims.get("username");
+
+                if (WEBGOAT_USER.equalsIgnoreCase(user)) {
+                    return trackProgress(success().build());
+                } else {
+                    return trackProgress(failed().feedback("jwt-secret-incorrect-user").feedbackArgs(user).build());
+                }
             }
         } catch (Exception e) {
-            trackProgress(failed().feedback("jwt-invalid-token").output(e.getMessage()).build());
+            return trackProgress(failed().feedback("jwt-invalid-token").output(e.getMessage()).build());
         }
     }
 }
diff --git a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java
index cf1e512db..94f829191 100644
--- a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java
+++ b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/JWTVotesEndpoint.java
@@ -21,6 +21,8 @@ import org.springframework.web.bind.annotation.*;
 import javax.annotation.PostConstruct;
 import javax.servlet.http.Cookie;
 import javax.servlet.http.HttpServletResponse;
+import java.time.Duration;
+import java.time.Instant;
 import java.util.Date;
 import java.util.Map;
 import java.util.concurrent.TimeUnit;
@@ -37,7 +39,7 @@ import static java.util.stream.Collectors.toList;
 @AssignmentHints({"jwt-change-token-hint1", "jwt-change-token-hint2", "jwt-change-token-hint3", "jwt-change-token-hint4", "jwt-change-token-hint5"})
 public class JWTVotesEndpoint extends AssignmentEndpoint {
 
-    private static final String JWT_PASSWORD = "victory";
+    public static final String JWT_PASSWORD = "victory";
     private static String validUsers = "TomJerrySylvester";
 
     private static int totalVotes = 38929;
@@ -65,11 +67,10 @@ public class JWTVotesEndpoint extends AssignmentEndpoint {
     @GetMapping("/login")
     public void login(@RequestParam("user") String user, HttpServletResponse response) {
         if (validUsers.contains(user)) {
-            Map<String, Object> claims = Maps.newHashMap();
+            Claims claims = Jwts.claims().setIssuedAt(Date.from(Instant.now().plus(Duration.ofDays(10))));
             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();
@@ -96,11 +97,11 @@ public class JWTVotesEndpoint extends AssignmentEndpoint {
                 Jwt jwt = Jwts.parser().setSigningKey(JWT_PASSWORD).parse(accessToken);
                 Claims claims = (Claims) jwt.getBody();
                 String user = (String) claims.get("user");
-                boolean isAdmin = Boolean.valueOf((String) claims.get("admin"));
                 if ("Guest".equals(user) || !validUsers.contains(user)) {
                     value.setSerializationView(Views.GuestView.class);
+                } else {
+                    value.setSerializationView(Views.UserView.class);
                 }
-                value.setSerializationView(isAdmin ? Views.AdminView.class : Views.UserView.class);
             } catch (JwtException e) {
                 value.setSerializationView(Views.GuestView.class);
             }
@@ -132,7 +133,8 @@ public class JWTVotesEndpoint extends AssignmentEndpoint {
     }
 
     @PostMapping("reset")
-    public @ResponseBody AttackResult resetVotes(@CookieValue(value = "access_token", required = false) String accessToken) {
+    public @ResponseBody
+    AttackResult resetVotes(@CookieValue(value = "access_token", required = false) String accessToken) {
         if (StringUtils.isEmpty(accessToken)) {
             return trackProgress(failed().feedback("jwt-invalid-token").build());
         } else {
diff --git a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/refresh/RefreshEndpoint.java b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/refresh/RefreshEndpoint.java
deleted file mode 100644
index d04cf8ef7..000000000
--- a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/refresh/RefreshEndpoint.java
+++ /dev/null
@@ -1,9 +0,0 @@
-package org.owasp.webgoat.plugin.refresh;
-
-public class RefreshEndpoint {
-
-  private static final String TOKEN = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJPbmxpbmUgSldUIEJ1aWxkZXIiLCJpYXQiOjE0OTUyODU3NDUsImV4cCI6MTQ5NTI4NTc0NSwiYXVkIjoid2ViZ29hdC5vcmciLCJzdWIiOiJ0b21Ad2ViZ29hdC5vcmciLCJuYW1lIjoiVG9tIiwiZW1haWwiOiJ0b21Ad2ViZ29hdC5jb20iLCJyb2xlIjoiQ2F0In0.NTd3E17JZlVKZk52Wq_AWZ0RDafV5KDRMuJner_zUn4";
-  private static final String JWT_KEY = "qwertyuiopasdfghjklzxcvbnm123456";
-
-
-}
diff --git a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/votes/Views.java b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/votes/Views.java
index 4a790c979..591769c5c 100644
--- a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/votes/Views.java
+++ b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/votes/Views.java
@@ -10,7 +10,4 @@ public class Views {
 
     public interface UserView extends GuestView {
     }
-
-    public interface AdminView extends UserView {
-    }
 }
diff --git a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/votes/Vote.java b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/votes/Vote.java
index ef79d5cd3..d9217d402 100644
--- a/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/votes/Vote.java
+++ b/webgoat-lessons/jwt/src/main/java/org/owasp/webgoat/plugin/votes/Vote.java
@@ -20,9 +20,6 @@ public class Vote {
     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)
diff --git a/webgoat-lessons/jwt/src/main/resources/i18n/WebGoatLabels.properties b/webgoat-lessons/jwt/src/main/resources/i18n/WebGoatLabels.properties
index 939de63ae..92cad6316 100644
--- a/webgoat-lessons/jwt/src/main/resources/i18n/WebGoatLabels.properties
+++ b/webgoat-lessons/jwt/src/main/resources/i18n/WebGoatLabels.properties
@@ -13,11 +13,13 @@ jwt-change-token-hint5=Submit the token by changing the algorithm to None and re
 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-secret-claims-missing=You are missing some claims, you should keep all the claims in the token
+jwt-secret-incorrect-user=The user is {0}, you need to change it to WebGoat
 
 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-hint4=Use the found access token in the Authorization: Bearer header and use your own 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 
diff --git a/webgoat-lessons/jwt/src/test/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpointTest.java b/webgoat-lessons/jwt/src/test/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpointTest.java
new file mode 100644
index 000000000..421857307
--- /dev/null
+++ b/webgoat-lessons/jwt/src/test/java/org/owasp/webgoat/plugin/JWTSecretKeyEndpointTest.java
@@ -0,0 +1,110 @@
+package org.owasp.webgoat.plugin;
+
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import org.hamcrest.CoreMatchers;
+import org.joda.time.Days;
+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.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Date;
+
+import static io.jsonwebtoken.SignatureAlgorithm.*;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.*;
+import static org.mockito.Mockito.when;
+import static org.owasp.webgoat.plugin.JWTSecretKeyEndpoint.JWT_SECRET;
+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 JWTSecretKeyEndpointTest 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");
+    }
+
+    private Claims createClaims(String username) {
+        Claims claims = Jwts.claims();
+        claims.put("admin", "true");
+        claims.put("user", "Tom");
+        claims.setExpiration(Date.from(Instant.now().plus(Duration.ofDays(1))));
+        claims.setIssuedAt(Date.from(Instant.now().plus(Duration.ofDays(1))));
+        claims.setIssuer("iss");
+        claims.setAudience("aud");
+        claims.setSubject("sub");
+        claims.put("username", username);
+        claims.put("Email", "webgoat@webgoat.io");
+        claims.put("Role", new String[]{"user"});
+        return claims;
+    }
+
+    @Test
+    public void solveAssignment() throws Exception {
+        Claims claims = createClaims("WebGoat");
+        String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact();
+
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret")
+                .param("token", token))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.lessonCompleted", is(true)));
+    }
+
+    @Test
+    public void solveAssignmentWithLowercase() throws Exception {
+        Claims claims = createClaims("webgoat");
+        String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact();
+
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret")
+                .param("token", token))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.lessonCompleted", is(true)));
+    }
+
+    @Test
+    public void oneOfClaimIsMissingShouldNotSolveAssignment() throws Exception {
+        Claims claims = createClaims("WebGoat");
+        claims.remove("aud");
+        String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact();
+
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret")
+                .param("token", token))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-secret-claims-missing"))));
+    }
+
+    @Test
+    public void incorrectUser() throws Exception {
+        Claims claims = createClaims("Tom");
+        String token = Jwts.builder().setClaims(claims).signWith(HS512, JWT_SECRET).compact();
+
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret")
+                .param("token", token))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-secret-incorrect-user", "default", "Tom"))));
+    }
+
+    @Test
+    public void incorrectToken() throws Exception {
+        Claims claims = createClaims("Tom");
+        String token = Jwts.builder().setClaims(claims).signWith(HS512, "wrong_password").compact();
+
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/secret")
+                .param("token", token))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token"))));
+    }
+}
\ No newline at end of file
diff --git a/webgoat-lessons/jwt/src/test/java/org/owasp/webgoat/plugin/JWTVotesEndpointTest.java b/webgoat-lessons/jwt/src/test/java/org/owasp/webgoat/plugin/JWTVotesEndpointTest.java
new file mode 100644
index 000000000..9c90c1678
--- /dev/null
+++ b/webgoat-lessons/jwt/src/test/java/org/owasp/webgoat/plugin/JWTVotesEndpointTest.java
@@ -0,0 +1,187 @@
+package org.owasp.webgoat.plugin;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+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 javax.servlet.http.Cookie;
+
+import java.util.Map;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.when;
+import static org.owasp.webgoat.plugin.JWTVotesEndpoint.JWT_PASSWORD;
+import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
+import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.cookie;
+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 JWTVotesEndpointTest 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 {
+        //Create new token and set alg to none and do not sign it
+        Claims claims = Jwts.claims();
+        claims.put("admin", "true");
+        claims.put("user", "Tom");
+        String token = Jwts.builder().setClaims(claims).setHeaderParam("alg", "none").compact();
+
+        //Call the reset endpoint
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/reset")
+                .contentType(MediaType.APPLICATION_JSON)
+                .cookie(new Cookie("access_token", token)))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.lessonCompleted", is(true)));
+    }
+
+    @Test
+    public void resetWithoutTokenShouldNotWork() throws Exception {
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/reset")
+                .contentType(MediaType.APPLICATION_JSON))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("jwt-invalid-token"))));
+    }
+
+    @Test
+    public void guestShouldNotGetAToken() throws Exception {
+        mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/login")
+                .contentType(MediaType.APPLICATION_JSON)
+                .param("user", "Guest"))
+                .andExpect(status().isUnauthorized()).andExpect(cookie().value("access_token", ""));
+    }
+
+    @Test
+    public void tomShouldGetAToken() throws Exception {
+        mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/login")
+                .contentType(MediaType.APPLICATION_JSON)
+                .param("user", "Tom"))
+                .andExpect(status().isOk()).andExpect(cookie().value("access_token", containsString("eyJhbGciOiJIUzUxMiJ9.")));
+    }
+
+    @Test
+    public void guestShouldNotSeeNumberOfVotes() throws Exception {
+        mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings")
+                .cookie(new Cookie("access_token", "")))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist())
+                .andExpect(jsonPath("$[0].votingAllowed").doesNotExist())
+                .andExpect(jsonPath("$[0].average").doesNotExist());
+    }
+
+    @Test
+    public void tomShouldSeeNumberOfVotes() throws Exception {
+        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/login")
+                .contentType(MediaType.APPLICATION_JSON)
+                .param("user", "Tom"))
+                .andExpect(status().isOk()).andReturn();
+
+        mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings")
+                .cookie(result.getResponse().getCookies()[0]))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$[0].numberOfVotes").exists())
+                .andExpect(jsonPath("$[0].votingAllowed").exists())
+                .andExpect(jsonPath("$[0].average").exists());
+    }
+
+    @Test
+    public void invalidTokenShouldSeeGuestView() throws Exception {
+        mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings")
+                .cookie(new Cookie("access_token", "abcd.efgh.ijkl")))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist())
+                .andExpect(jsonPath("$[0].votingAllowed").doesNotExist())
+                .andExpect(jsonPath("$[0].average").doesNotExist());
+    }
+
+    @Test
+    public void tomShouldBeAbleToVote() throws Exception {
+        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/login")
+                .contentType(MediaType.APPLICATION_JSON)
+                .param("user", "Tom"))
+                .andExpect(status().isOk()).andReturn();
+        Cookie cookie = result.getResponse().getCookie("access_token");
+
+        result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings")
+                .cookie(cookie))
+                .andExpect(status().isOk()).andDo(print()).andReturn();
+        Object[] nodes = new ObjectMapper().readValue(result.getResponse().getContentAsString(), Object[].class);
+        int currentNumberOfVotes = (int) findNodeByTitle(nodes, "Admin lost password").get("numberOfVotes");
+
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password")
+                .cookie(cookie))
+                .andExpect(status().isAccepted());
+        result = mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings")
+                .cookie(cookie))
+                .andExpect(status().isOk()).andReturn();
+        nodes = new ObjectMapper().readValue(result.getResponse().getContentAsString(), Object[].class);
+        int numberOfVotes = (int) findNodeByTitle(nodes, "Admin lost password").get("numberOfVotes");
+        assertThat(numberOfVotes).isEqualTo(currentNumberOfVotes + 1);
+    }
+
+    private Map<String, Object> findNodeByTitle(Object[] nodes, String title) {
+        for (Object n : nodes) {
+            Map<String, Object> node = (Map<String, Object>) n;
+            if (node.get("title").equals(title)) {
+                return node;
+            }
+        }
+        return null;
+    }
+
+    @Test
+    public void guestShouldNotBeAbleToVote() throws Exception {
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password")
+                .cookie(new Cookie("access_token", "")))
+                .andExpect(status().isUnauthorized());
+    }
+
+    @Test
+    public void unknownUserWithValidTokenShouldNotBeAbleToVote() throws Exception {
+        Claims claims = Jwts.claims();
+        claims.put("admin", "true");
+        claims.put("user", "Intruder");
+        String token = Jwts.builder().signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD).setClaims(claims).compact();
+
+        mockMvc.perform(MockMvcRequestBuilders.post("/JWT/votings/Admin lost password")
+                .cookie(new Cookie("access_token", token)))
+                .andExpect(status().isUnauthorized());
+    }
+
+    @Test
+    public void unknownUserShouldSeeGuestView() throws Exception {
+        Claims claims = Jwts.claims();
+        claims.put("admin", "true");
+        claims.put("user", "Intruder");
+        String token = Jwts.builder().signWith(io.jsonwebtoken.SignatureAlgorithm.HS512, JWT_PASSWORD).setClaims(claims).compact();
+
+        mockMvc.perform(MockMvcRequestBuilders.get("/JWT/votings/")
+                .cookie(new Cookie("access_token", token)))
+                .andExpect(status().isOk())
+                .andExpect(jsonPath("$[0].numberOfVotes").doesNotExist())
+                .andExpect(jsonPath("$[0].votingAllowed").doesNotExist())
+                .andExpect(jsonPath("$[0].average").doesNotExist());
+    }
+
+
+}
\ No newline at end of file