diff --git a/src/main/java/app/coronawarn/verification/portal/SecurityConfig.java b/src/main/java/app/coronawarn/verification/portal/SecurityConfig.java index 422bf04..9b98dbf 100644 --- a/src/main/java/app/coronawarn/verification/portal/SecurityConfig.java +++ b/src/main/java/app/coronawarn/verification/portal/SecurityConfig.java @@ -26,6 +26,7 @@ import java.util.concurrent.ConcurrentHashMap; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.keycloak.adapters.springboot.KeycloakSpringBootConfigResolver; import org.keycloak.adapters.springsecurity.KeycloakSecurityComponents; @@ -57,20 +58,24 @@ @Configuration @EnableWebSecurity @ComponentScan(basePackageClasses = KeycloakSecurityComponents.class) -class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { +@RequiredArgsConstructor +public class SecurityConfig extends KeycloakWebSecurityConfigurerAdapter { - private static final String ROLE_C19HOTLINE = "c19hotline"; + public static final String ROLE_C19HOTLINE = "c19hotline"; + public static final String ROLE_C19HOTLINE_EVENT = "c19hotline_event"; private static final String ACTUATOR_ROUTE = "/actuator/**"; private static final String SAMESITE_LAX = "Lax"; private static final String OAUTH_TOKEN_REQUEST_STATE_COOKIE = "OAuth_Token_Request_State"; private static final String SESSION_COOKIE = "SESSION"; - @Autowired - private VerificationPortalHttpFilter verificationPortalHttpFilter; + private final VerificationPortalHttpFilter verificationPortalHttpFilter; + /** + * Configures Keycloak. + */ @Autowired - public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception { + public void configureGlobal(AuthenticationManagerBuilder auth) { KeycloakAuthenticationProvider keycloakAuthenticationProvider = keycloakAuthenticationProvider(); keycloakAuthenticationProvider.setGrantedAuthoritiesMapper(new SimpleAuthorityMapper()); auth.authenticationProvider(keycloakAuthenticationProvider); @@ -97,10 +102,13 @@ protected void configure(HttpSecurity http) throws Exception { .authorizeRequests() .mvcMatchers(HttpMethod.GET, ACTUATOR_ROUTE).permitAll() .antMatchers(VerificationPortalController.ROUTE_TELETAN) - .hasRole(ROLE_C19HOTLINE) + .hasAnyRole(ROLE_C19HOTLINE, ROLE_C19HOTLINE_EVENT) .anyRequest().authenticated(); } + /** + * Configures Cookie Serializer. + */ @Bean public CookieSerializer defaultCookieSerializer() { DefaultCookieSerializer cookieSerializer = new DefaultCookieSerializer(); diff --git a/src/main/java/app/coronawarn/verification/portal/client/VerificationServerClient.java b/src/main/java/app/coronawarn/verification/portal/client/VerificationServerClient.java index 458ea6f..e0067a0 100644 --- a/src/main/java/app/coronawarn/verification/portal/client/VerificationServerClient.java +++ b/src/main/java/app/coronawarn/verification/portal/client/VerificationServerClient.java @@ -31,7 +31,8 @@ configuration = VerificationServerClientConfig.class) public interface VerificationServerClient { - public static final String HEADER_NAME_AUTHORIZATION = "Authorization"; + String HEADER_NAME_AUTHORIZATION = "Authorization"; + String HEADER_NAME_TELETAN_TYPE = "X-CWA-TELETAN-TYPE"; /** * Call the verification service to get teletan from token. @@ -43,6 +44,8 @@ public interface VerificationServerClient { produces = MediaType.APPLICATION_JSON_VALUE, consumes = MediaType.APPLICATION_JSON_VALUE ) - TeleTan createTeleTan(@RequestHeader(HEADER_NAME_AUTHORIZATION) String token); + TeleTan createTeleTan( + @RequestHeader(HEADER_NAME_AUTHORIZATION) String token, + @RequestHeader(HEADER_NAME_TELETAN_TYPE) String teleTanType); } diff --git a/src/main/java/app/coronawarn/verification/portal/controller/VerificationPortalController.java b/src/main/java/app/coronawarn/verification/portal/controller/VerificationPortalController.java index dea89f7..3d00017 100644 --- a/src/main/java/app/coronawarn/verification/portal/controller/VerificationPortalController.java +++ b/src/main/java/app/coronawarn/verification/portal/controller/VerificationPortalController.java @@ -21,6 +21,7 @@ package app.coronawarn.verification.portal.controller; +import app.coronawarn.verification.portal.SecurityConfig; import app.coronawarn.verification.portal.client.TeleTan; import app.coronawarn.verification.portal.service.TeleTanService; import feign.FeignException; @@ -38,6 +39,7 @@ import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; @@ -92,6 +94,11 @@ public class VerificationPortalController { private static final String ATTR_TELETAN = "teleTAN"; private static final String ATTR_USER = "userName"; private static final String ATTR_PW_RESET_URL = "pwResetUrl"; + private static final String ATTR_ROLE_TEST = "role_test"; + private static final String ATTR_ROLE_EVENT = "role_event"; + + private static final String TELETAN_TYPE_TEST = "TEST"; + private static final String TELETAN_TYPE_EVENT = "EVENT"; /** * The Keycloak password reset URL. @@ -99,7 +106,7 @@ public class VerificationPortalController { @Value("${keycloak-pw.reset-url}") private String pwResetUrl; - private static final Map rateLimitingUserMap = new ConcurrentHashMap(); + private static final Map rateLimitingUserMap = new ConcurrentHashMap<>(); @Value("${rateLimiting.enabled}") private boolean rateLimitingEnabled; @@ -142,6 +149,7 @@ public String start(HttpServletRequest request, Model model) { if (model != null) { model.addAttribute(ATTR_USER, user.replace("<", "").replace(">", "")); model.addAttribute(ATTR_PW_RESET_URL, pwResetUrl); + setRoleDependentAttributes(model, principal); } HttpSession session = request.getSession(); @@ -161,12 +169,19 @@ public String start(HttpServletRequest request, Model model) { * @return the name of the Thymeleaf template to be used for the HTML page */ @PostMapping(value = ROUTE_TELETAN) - public String teletan(HttpServletRequest request, Model model) { + public String teletan( + HttpServletRequest request, + Model model, + @ModelAttribute("EVENT") String eventButton, + @ModelAttribute("TEST") String testButton) { + TeleTan teleTan = new TeleTan("123456789"); KeycloakAuthenticationToken principal = (KeycloakAuthenticationToken) request .getUserPrincipal(); String user = ((KeycloakPrincipal) principal.getPrincipal()).getName(); + String teleTanType = ""; + // initially the TEMPLATE_INDEX is used (without showing the teleTAN) String template = TEMPLATE_START; HttpSession session = request.getSession(); @@ -180,7 +195,13 @@ public String teletan(HttpServletRequest request, Model model) { } try { - teleTan = teleTanService.createTeleTan(token); + if (!eventButton.isEmpty()) { + teleTan = teleTanService.createTeleTan(token, TELETAN_TYPE_EVENT); + teleTanType = TELETAN_TYPE_EVENT; + } else if (!testButton.isEmpty()) { + teleTan = teleTanService.createTeleTan(token, TELETAN_TYPE_TEST); + teleTanType = TELETAN_TYPE_TEST; + } } catch (FeignException e) { if (e.status() == HttpStatus.TOO_MANY_REQUESTS.value()) { throw new ServerRateLimitationException("Too many requests. Please wait a moment."); @@ -189,7 +210,7 @@ public String teletan(HttpServletRequest request, Model model) { } } - log.info("TeleTan successfully retrieved for user: {}", user); + log.info("TeleTan Type {} successfully retrieved for user: {}", teleTanType,user); template = TEMPLATE_TELETAN; } session.setAttribute(SESSION_ATTR_TELETAN, "TeleTAN"); @@ -198,6 +219,7 @@ public String teletan(HttpServletRequest request, Model model) { model.addAttribute(ATTR_TELETAN, teleTan.getValue().replace("<", "").replace(">", "")); model.addAttribute(ATTR_USER, user.replace("<", "").replace(">", "")); model.addAttribute(ATTR_PW_RESET_URL, pwResetUrl); + setRoleDependentAttributes(model, principal); } return template; } @@ -230,4 +252,13 @@ public String logout(HttpServletRequest request) { } return "redirect:" + TEMPLATE_START; } + + private void setRoleDependentAttributes(Model model, KeycloakAuthenticationToken token) { + model.addAttribute(ATTR_ROLE_TEST, token.getAuthorities().stream() + .anyMatch(grantedAuthority -> grantedAuthority.getAuthority().equals("ROLE_" + SecurityConfig.ROLE_C19HOTLINE))); + + model.addAttribute(ATTR_ROLE_EVENT, token.getAuthorities().stream() + .anyMatch(grantedAuthority -> + grantedAuthority.getAuthority().equals("ROLE_" + SecurityConfig.ROLE_C19HOTLINE_EVENT))); + } } diff --git a/src/main/java/app/coronawarn/verification/portal/service/TeleTanService.java b/src/main/java/app/coronawarn/verification/portal/service/TeleTanService.java index 3851628..e1afe7c 100644 --- a/src/main/java/app/coronawarn/verification/portal/service/TeleTanService.java +++ b/src/main/java/app/coronawarn/verification/portal/service/TeleTanService.java @@ -2,7 +2,6 @@ import app.coronawarn.verification.portal.client.TeleTan; import app.coronawarn.verification.portal.client.VerificationServerClient; -import lombok.NonNull; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @@ -11,14 +10,13 @@ @Service @RequiredArgsConstructor public class TeleTanService { - - @NonNull - private VerificationServerClient verificationServerClient; + + private final VerificationServerClient verificationServerClient; public static final String TOKEN_PREFIX = "Bearer "; - public TeleTan createTeleTan(String token) { - return verificationServerClient.createTeleTan(TOKEN_PREFIX + token); + public TeleTan createTeleTan(String token, String teleTanType) { + return verificationServerClient.createTeleTan(TOKEN_PREFIX + token, teleTanType); } } diff --git a/src/main/resources/templates/start.html b/src/main/resources/templates/start.html index bf0c7be..0e1bbc5 100644 --- a/src/main/resources/templates/start.html +++ b/src/main/resources/templates/start.html @@ -30,8 +30,10 @@
TeleTAN erzeugen
Erzeugen Sie eine neue TeleTAN für einen Patienten.
+
Sie besitzen nicht die benötigten Berechtigungen zum Erzeugen von TeleTAN.
- + +
diff --git a/src/main/resources/templates/teletan.html b/src/main/resources/templates/teletan.html index 98c00dd..2365238 100644 --- a/src/main/resources/templates/teletan.html +++ b/src/main/resources/templates/teletan.html @@ -34,7 +34,8 @@
Die neue TeleTAN lautet
- + +
diff --git a/src/test/java/app/coronawarn/verification/portal/controller/VerificationPortalControllerTest.java b/src/test/java/app/coronawarn/verification/portal/controller/VerificationPortalControllerTest.java index 0177218..99503fb 100644 --- a/src/test/java/app/coronawarn/verification/portal/controller/VerificationPortalControllerTest.java +++ b/src/test/java/app/coronawarn/verification/portal/controller/VerificationPortalControllerTest.java @@ -21,6 +21,19 @@ package app.coronawarn.verification.portal.controller; +import static org.hamcrest.Matchers.equalTo; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.when; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.redirectedUrl; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.request; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; + import app.coronawarn.verification.portal.client.TeleTan; import app.coronawarn.verification.portal.service.TeleTanService; import com.c4_soft.springaddons.security.oauth2.test.annotations.keycloak.WithMockKeycloakAuth; @@ -29,16 +42,10 @@ import feign.Request; import java.util.Collections; import lombok.extern.slf4j.Slf4j; -import static org.hamcrest.Matchers.equalTo; -import static org.mockito.ArgumentMatchers.any; - import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mockito; - -import static org.mockito.BDDMockito.*; -import static org.mockito.Mockito.when; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; @@ -48,9 +55,6 @@ import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.TestPropertySource; import org.springframework.test.web.servlet.MockMvc; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @Slf4j @@ -101,24 +105,65 @@ public void testIndex() throws Exception { * @throws Exception if the test cannot be performed. */ @Test - @WithMockKeycloakAuth(name = "tester", value = "Role_Test") + @WithMockKeycloakAuth(name = "tester1", authorities = {"ROLE_c19hotline", "ROLE_c19hotline_event"}) public void testStart() throws Exception { log.info("process testStart() RequestMethod.GET"); mockMvc.perform(get("/cwa/start")) .andExpect(status().isOk()) .andExpect(view().name("start")) - .andExpect(model().attribute("userName", equalTo("tester"))) + .andExpect(model().attribute("userName", equalTo("tester1"))) + .andExpect(model().attribute("role_test", equalTo(true))) + .andExpect(model().attribute("role_event", equalTo(true))) .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); String TOKEN_ATTR_NAME = "org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository.CSRF_TOKEN"; log.info("process testStart() RequestMethod.POST"); mockMvc.perform(post("/cwa/start") - .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) - .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) + .andExpect(status().isOk()) + .andExpect(view().name("start")) + .andExpect(model().attribute("userName", equalTo("tester1"))) + .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); + } + + @Test + @WithMockKeycloakAuth(name = "tester2", authorities = {"ROLE_c19hotline"}) + public void testStartOnlyTestRole() throws Exception { + log.info("process testStartOnlyTestRole()"); + mockMvc.perform(get("/cwa/start")) + .andExpect(status().isOk()) + .andExpect(view().name("start")) + .andExpect(model().attribute("userName", equalTo("tester2"))) + .andExpect(model().attribute("role_test", equalTo(true))) + .andExpect(model().attribute("role_event", equalTo(false))) + .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); + } + + @Test + @WithMockKeycloakAuth(name = "tester3", authorities = {"ROLE_c19hotline_event"}) + public void testStartOnlyEventRole() throws Exception { + log.info("process testStartOnlyEventRole()"); + mockMvc.perform(get("/cwa/start")) .andExpect(status().isOk()) .andExpect(view().name("start")) - .andExpect(model().attribute("userName", equalTo("tester"))) + .andExpect(model().attribute("userName", equalTo("tester3"))) + .andExpect(model().attribute("role_test", equalTo(false))) + .andExpect(model().attribute("role_event", equalTo(true))) + .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); + } + + @Test + @WithMockKeycloakAuth(name = "tester4", authorities = {}) + public void testStartNoRole() throws Exception { + log.info("process testStartNoRole()"); + mockMvc.perform(get("/cwa/start")) + .andExpect(status().isOk()) + .andExpect(view().name("start")) + .andExpect(model().attribute("userName", equalTo("tester4"))) + .andExpect(model().attribute("role_test", equalTo(false))) + .andExpect(model().attribute("role_event", equalTo(false))) .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); } @@ -128,7 +173,7 @@ public void testStart() throws Exception { * @throws Exception if the test cannot be performed. */ @Test - @WithMockKeycloakAuth(name = "tester", value = "Role_Test") + @WithMockKeycloakAuth(name = "tester5", value = "Role_Test") public void testStartNotFound() throws Exception { log.info("process testStartNotFound()"); mockMvc.perform(get("/corona/start")) @@ -141,25 +186,110 @@ public void testStartNotFound() throws Exception { * @throws Exception if the test cannot be performed. */ @Test - @WithMockKeycloakAuth(name = "tester", value = "Role_Test") - public void testTeletan() throws Exception { - log.info("process testTeletan()"); + @WithMockKeycloakAuth(name = "tester6", authorities = {"ROLE_c19hotline", "ROLE_c19hotline_event"}) + public void testTeletanEvent() throws Exception { + log.info("process testTeletanEvent()"); - when(teleTanService.createTeleTan(any(String.class))).thenReturn(new TeleTan("123454321")); + when(teleTanService.createTeleTan(any(String.class), eq("EVENT"))).thenReturn(new TeleTan("123454321")); mockMvc.perform(post("/cwa/teletan") - .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) - .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE) + .param("EVENT", "Event Button Clicked") + .param("TEST", "")) .andExpect(status().isOk()) .andExpect(view().name(TELETAN_NAME)) - .andExpect(model().attribute("userName", equalTo("tester"))) + .andExpect(model().attribute("userName", equalTo("tester6"))) .andExpect(model().attribute("teleTAN", equalTo("123454321"))) + .andExpect(model().attribute("role_test", equalTo(true))) + .andExpect(model().attribute("role_event", equalTo(true))) .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); // check rate limiting mockMvc.perform(post("/cwa/teletan") - .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) - .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) + .andExpect(status().isTooManyRequests()); + } + + @Test + @WithMockKeycloakAuth(name = "tester7", authorities = {"ROLE_c19hotline", "ROLE_c19hotline_event"}) + public void testTeletanTest() throws Exception { + log.info("process testTeletanTest()"); + + when(teleTanService.createTeleTan(any(String.class), eq("TEST"))).thenReturn(new TeleTan("123454321")); + + mockMvc.perform(post("/cwa/teletan") + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE) + .param("EVENT", "") + .param("TEST", "TEST Button clicked")) + .andExpect(status().isOk()) + .andExpect(view().name(TELETAN_NAME)) + .andExpect(model().attribute("userName", equalTo("tester7"))) + .andExpect(model().attribute("teleTAN", equalTo("123454321"))) + .andExpect(model().attribute("role_test", equalTo(true))) + .andExpect(model().attribute("role_event", equalTo(true))) + .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); + + // check rate limiting + mockMvc.perform(post("/cwa/teletan") + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) + .andExpect(status().isTooManyRequests()); + } + + @Test + @WithMockKeycloakAuth(name = "tester8", authorities = {"ROLE_c19hotline"}) + public void testRoleMappingOnlyHotline() throws Exception { + log.info("process testRoleMappingOnlyHotline()"); + + when(teleTanService.createTeleTan(any(String.class), eq("TEST"))).thenReturn(new TeleTan("123454321")); + + mockMvc.perform(post("/cwa/teletan") + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE) + .param("EVENT", "") + .param("TEST", "TEST Button clicked")) + .andExpect(status().isOk()) + .andExpect(view().name(TELETAN_NAME)) + .andExpect(model().attribute("userName", equalTo("tester8"))) + .andExpect(model().attribute("teleTAN", equalTo("123454321"))) + .andExpect(model().attribute("role_test", equalTo(true))) + .andExpect(model().attribute("role_event", equalTo(false))) + .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); + + // check rate limiting + mockMvc.perform(post("/cwa/teletan") + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) + .andExpect(status().isTooManyRequests()); + } + + @Test + @WithMockKeycloakAuth(name = "tester9", authorities = {"ROLE_c19hotline_event"}) + public void testRoleMappingOnlyEvent() throws Exception { + log.info("process testRoleMappingOnlyEvent()"); + + when(teleTanService.createTeleTan(any(String.class), eq("TEST"))).thenReturn(new TeleTan("123454321")); + + mockMvc.perform(post("/cwa/teletan") + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE) + .param("EVENT", "") + .param("TEST", "TEST Button clicked")) + .andExpect(status().isOk()) + .andExpect(view().name(TELETAN_NAME)) + .andExpect(model().attribute("userName", equalTo("tester9"))) + .andExpect(model().attribute("teleTAN", equalTo("123454321"))) + .andExpect(model().attribute("role_test", equalTo(false))) + .andExpect(model().attribute("role_event", equalTo(true))) + .andExpect(request().sessionAttribute(TELETAN_NAME, equalTo(TELETAN_VALUE))); + + // check rate limiting + mockMvc.perform(post("/cwa/teletan") + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) .andExpect(status().isTooManyRequests()); } @@ -174,32 +304,36 @@ public void testLogout() throws Exception { log.info("process testLogout()"); mockMvc.perform(post("/cwa/logout") - .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken())) + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken())) .andExpect(redirectedUrl("start")) .andExpect(status().isFound()); } @Test - @WithMockKeycloakAuth(name = "tester2", value = "Role_Test") + @WithMockKeycloakAuth(name = "tester10", value = "ROLE_c19hotline") public void testIfRateLimitExceptionIsHandledCorrectly() throws Exception { Request dummyRequest = Request.create(Request.HttpMethod.GET, "url", Collections.emptyMap(), null, null, null); - Mockito.doThrow(new FeignException.TooManyRequests("", dummyRequest, null)).when(teleTanService).createTeleTan(any(String.class)); + Mockito.doThrow(new FeignException.TooManyRequests("", dummyRequest, null)).when(teleTanService).createTeleTan(any(String.class), any(String.class)); mockMvc.perform(post("/cwa/teletan") - .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) - .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) + .param("EVENT", "") + .param("TEST", "TEST Button clicked") + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)) .andExpect(status().isTooManyRequests()); } @Test - @WithMockKeycloakAuth(name = "tester2", value = "Role_Test") - public void testIfAnyOtherExceptionIsJustForwared() throws Exception { - given(teleTanService.createTeleTan(any(String.class))).willAnswer( invocation -> { throw new Exception("Dummy Exception"); }); - Assertions.assertThrows(Exception.class, () -> { - mockMvc.perform(post("/cwa/teletan") - .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) - .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE)); + @WithMockKeycloakAuth(name = "tester11", value = "Role_Test") + public void testIfAnyOtherExceptionIsJustForwared() { + given(teleTanService.createTeleTan(any(String.class), any(String.class))).willAnswer(invocation -> { + throw new Exception("Dummy Exception"); }); + Assertions.assertThrows(Exception.class, () -> mockMvc.perform(post("/cwa/teletan") + .param("EVENT", "") + .param("TEST", "TEST Button clicked") + .sessionAttr(TOKEN_ATTR_NAME, csrfToken).param(csrfToken.getParameterName(), csrfToken.getToken()) + .sessionAttr(TELETAN_NAME, TELETAN_VALUE).param(TELETAN_NAME, TELETAN_VALUE))); } } diff --git a/src/test/java/app/coronawarn/verification/portal/service/TeleTanServiceTest.java b/src/test/java/app/coronawarn/verification/portal/service/TeleTanServiceTest.java index ddd30d1..3b5a6b2 100644 --- a/src/test/java/app/coronawarn/verification/portal/service/TeleTanServiceTest.java +++ b/src/test/java/app/coronawarn/verification/portal/service/TeleTanServiceTest.java @@ -21,19 +21,16 @@ package app.coronawarn.verification.portal.service; +import static org.assertj.core.api.Assertions.assertThat; + import app.coronawarn.verification.portal.client.TeleTan; import app.coronawarn.verification.portal.client.VerificationServerClient; import lombok.extern.slf4j.Slf4j; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.InjectMocks; -import org.mockito.Mock; import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; - -import static org.assertj.core.api.Assertions.assertThat; +import org.springframework.boot.test.mock.mockito.MockBean; @Slf4j @SpringBootTest @@ -41,26 +38,25 @@ public class TeleTanServiceTest { public static final String TEST_TELE_TAN = "FE9A5MAK6C"; public static final String TEST_TOKEN = "0815"; + public static final String TEST_TELE_TAN_TYPE = "TEST"; @Autowired - @InjectMocks private TeleTanService teleTanService; - @Mock + @MockBean private VerificationServerClient clientMock; - @BeforeEach - public void setUp() { - MockitoAnnotations.initMocks(this); - } - /** * Test of createTeleTan method, of class TeleTanService. */ @Test public void testCreateTeleTan() { log.info("process testCreateTeleTan()"); - Mockito.doReturn(new TeleTan(TEST_TELE_TAN)).when(clientMock).createTeleTan(TeleTanService.TOKEN_PREFIX + TEST_TOKEN); - assertThat(teleTanService.createTeleTan(TEST_TOKEN).equals(new TeleTan(TEST_TELE_TAN))); + + Mockito.when(clientMock.createTeleTan(TeleTanService.TOKEN_PREFIX + TEST_TOKEN, TEST_TELE_TAN_TYPE)) + .thenReturn(new TeleTan(TEST_TELE_TAN)); + + + assertThat(teleTanService.createTeleTan(TEST_TOKEN, TEST_TELE_TAN_TYPE)).isEqualTo(new TeleTan(TEST_TELE_TAN)); } }