Add test case for security question assignment and the tracking is now

done with a session scoped bean
This commit is contained in:
Nanne Baars 2019-08-06 19:03:40 +02:00
parent 18eee4df58
commit e01c2a35ce
4 changed files with 145 additions and 30 deletions

View File

@ -3,6 +3,7 @@ package org.owasp.webgoat.plugin;
import org.owasp.webgoat.assignments.AssignmentEndpoint; import org.owasp.webgoat.assignments.AssignmentEndpoint;
import org.owasp.webgoat.assignments.AssignmentPath; import org.owasp.webgoat.assignments.AssignmentPath;
import org.owasp.webgoat.assignments.AttackResult; import org.owasp.webgoat.assignments.AttackResult;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RequestParam;
@ -11,44 +12,53 @@ import org.springframework.web.bind.annotation.ResponseBody;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import static java.util.Optional.of;
/** /**
* Assignment for picking a good security question. * Assignment for picking a good security question.
*
* @author Tobias Melzer * @author Tobias Melzer
* @since 11.12.18 * @since 11.12.18
*/ */
@AssignmentPath("/PasswordReset/SecurityQuestions") @AssignmentPath("/PasswordReset/SecurityQuestions")
public class SecurityQuestionAssignment extends AssignmentEndpoint { public class SecurityQuestionAssignment extends AssignmentEndpoint {
private static int triedQuestions = 0; @Autowired
private TriedQuestions triedQuestions;
private static Map<String, String> questions; private static Map<String, String> questions;
static { static {
questions = new HashMap<>(); questions = new HashMap<>();
questions.put("What is your favorite animal?", "The answer can easily be guessed and figured out through social media."); questions.put("What is your favorite animal?", "The answer can easily be guessed and figured out through social media.");
questions.put("In what year was your mother born?", "Can be easily guessed."); questions.put("In what year was your mother born?", "Can be easily guessed.");
questions.put("What was the time you were born?", "This may first seem like a good question, but you most likely dont know the exact time, so it might be hard to remember."); questions.put("What was the time you were born?", "This may first seem like a good question, but you most likely dont know the exact time, so it might be hard to remember.");
questions.put("What is the name of the person you first kissed?", "Can be figured out through social media, or even guessed by trying the most common names."); questions.put("What is the name of the person you first kissed?", "Can be figured out through social media, or even guessed by trying the most common names.");
questions.put("What was the house number and street name you lived in as a child?", "Answer can be figured out through social media, or worse it might be your current address."); questions.put("What was the house number and street name you lived in as a child?", "Answer can be figured out through social media, or worse it might be your current address.");
questions.put("In what town or city was your first full time job?", "In times of LinkedIn and Facebook, the answer can be figured out quite easily."); questions.put("In what town or city was your first full time job?", "In times of LinkedIn and Facebook, the answer can be figured out quite easily.");
questions.put("In what city were you born?", "Easy to figure out through social media."); questions.put("In what city were you born?", "Easy to figure out through social media.");
questions.put("What was the last name of your favorite teacher in grade three?", "Most people would probably not know the answer to that."); questions.put("What was the last name of your favorite teacher in grade three?", "Most people would probably not know the answer to that.");
questions.put("What is the name of a college/job you applied to but didn't attend?", "It might not be easy to remember and an hacker could just try some company's/colleges in your area."); questions.put("What is the name of a college/job you applied to but didn't attend?", "It might not be easy to remember and an hacker could just try some company's/colleges in your area.");
questions.put("What are the last 5 digits of your drivers license?", "Is subject to change, and the last digit of your driver license might follow a specific pattern. (For example your birthday)."); questions.put("What are the last 5 digits of your drivers license?", "Is subject to change, and the last digit of your driver license might follow a specific pattern. (For example your birthday).");
questions.put("What was your childhood nickname?", "Not all people had a nickname."); questions.put("What was your childhood nickname?", "Not all people had a nickname.");
questions.put("Who was your childhood hero?", "Most Heroes we had as a child where quite obvious ones, like Superman for example."); questions.put("Who was your childhood hero?", "Most Heroes we had as a child where quite obvious ones, like Superman for example.");
questions.put("On which wrist do you were your watch?", "There are only to possible real answers, so really easy to guess."); questions.put("On which wrist do you were your watch?", "There are only to possible real answers, so really easy to guess.");
questions.put("What is your favorite color?", "Can easily be guessed."); questions.put("What is your favorite color?", "Can easily be guessed.");
} }
@RequestMapping(method = RequestMethod.POST)
public @RequestMapping(method = RequestMethod.POST)
@ResponseBody @ResponseBody
AttackResult completed(@RequestParam String question) { public AttackResult completed(@RequestParam String question) {
triedQuestions+=1; var answer = of(questions.get(question));
String answer = questions.get(question); if (answer.isPresent()) {
answer = "<b>" + answer + "</b>"; triedQuestions.incr(question);
if(triedQuestions > 1) if (triedQuestions.isComplete()) {
return trackProgress(success().output(answer).build()); return trackProgress(success().output("<b>" + answer + "</b>").build());
return failed().output(answer).build(); }
} }
return informationMessage()
.feedback("password-questions-one-successful")
.output(answer.orElse("Unknown question, please try again..."))
.build();
}
} }

View File

@ -0,0 +1,22 @@
package org.owasp.webgoat.plugin;
import com.google.common.collect.Sets;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.SessionScope;
import java.util.Set;
@Component
@SessionScope
public class TriedQuestions {
private Set<String> answeredQuestions = Sets.newHashSet();
public void incr(String question) {
answeredQuestions.add(question);
}
public boolean isComplete() {
return answeredQuestions.size() > 1;
}
}

View File

@ -7,6 +7,7 @@ password-reset-simple.email_mismatch=Of course you can send mail to user {0} how
password-questions-wrong-user=You need to find a different user you are logging in with 'webgoat'. password-questions-wrong-user=You need to find a different user you are logging in with 'webgoat'.
password-questions-unknown-user=User {0} is not a valid user. password-questions-unknown-user=User {0} is not a valid user.
password-questions-one-successful=You answered one question successfully please try another one.
password-reset-no-user=Please supply a valid e-mail address. password-reset-no-user=Please supply a valid e-mail address.
password-reset-solved=Congratulations you solved the assignment, please type in the following code in the e-mail field: {0} password-reset-solved=Congratulations you solved the assignment, please type in the following code in the e-mail field: {0}

View File

@ -0,0 +1,82 @@
package org.owasp.webgoat.plugin;
import org.hamcrest.CoreMatchers;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.owasp.webgoat.plugins.LessonTest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
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 SecurityQuestionAssignmentTest extends LessonTest {
@Before
public void setup() {
PasswordReset assignment = new PasswordReset();
Mockito.when(webSession.getCurrentLesson()).thenReturn(assignment);
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
Mockito.when(webSession.getUserName()).thenReturn("unit-test");
}
@Test
public void oneQuestionShouldNotSolveTheAssignment() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions")
.param("question", "What is your favorite animal?"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("password-questions-one-successful"))))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)))
.andExpect(jsonPath("$.output", CoreMatchers.notNullValue()));
}
@Test
public void twoQuestionsShouldSolveTheAssignment() throws Exception {
MockHttpSession mocksession = new MockHttpSession();
mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions")
.param("question", "What is your favorite animal?").session(mocksession))
.andExpect(status().isOk())
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions")
.param("question", "In what year was your mother born?").session(mocksession))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("assignment.solved"))))
.andExpect(jsonPath("$.output", CoreMatchers.notNullValue()))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
}
@Test
public void answeringSameQuestionTwiceShouldNotSolveAssignment() throws Exception {
MockHttpSession mocksession = new MockHttpSession();
mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions")
.param("question", "What is your favorite animal?").session(mocksession))
.andExpect(status().isOk());
mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions")
.param("question", "What is your favorite animal?").session(mocksession))
.andExpect(status().isOk())
.andExpect(jsonPath("$.feedback", CoreMatchers.is(messages.getMessage("password-questions-one-successful"))))
.andExpect(jsonPath("$.output", CoreMatchers.notNullValue()))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}
@Test
public void solvingForOneUserDoesNotSolveForOtherUser() throws Exception {
MockHttpSession mocksession = new MockHttpSession();
mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions")
.param("question", "What is your favorite animal?").session(mocksession));
mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions")
.param("question", "In what year was your mother born?").session(mocksession))
.andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(true)));
MockHttpSession mocksession2 = new MockHttpSession();
mockMvc.perform(MockMvcRequestBuilders.post("/PasswordReset/SecurityQuestions")
.param("question", "What is your favorite animal?").session(mocksession2)).
andExpect(jsonPath("$.lessonCompleted", CoreMatchers.is(false)));
}
}