Skip to content
This repository has been archived by the owner on May 16, 2023. It is now read-only.

Feat: UI controls for Event TeleTan #111

Merged
merged 3 commits into from
Aug 19, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);

}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -92,14 +94,19 @@ 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.
*/
@Value("${keycloak-pw.reset-url}")
private String pwResetUrl;

private static final Map<String, LocalDateTime> rateLimitingUserMap = new ConcurrentHashMap<String, LocalDateTime>();
private static final Map<String, LocalDateTime> rateLimitingUserMap = new ConcurrentHashMap<>();

@Value("${rateLimiting.enabled}")
private boolean rateLimitingEnabled;
Expand Down Expand Up @@ -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();
Expand All @@ -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();
Expand All @@ -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.");
Expand All @@ -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");
Expand All @@ -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;
}
Expand Down Expand Up @@ -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)));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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);
}

}
4 changes: 3 additions & 1 deletion src/main/resources/templates/start.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,10 @@
<!-- BEGIN page specific content -->
<div class="text-big" style="top: 210px;">TeleTAN erzeugen</div>
<div class="text" style="top: 300px;">Erzeugen Sie eine neue TeleTAN für einen Patienten.</div>
<div th:if="${!role_test && !role_event}" class="text-error" style="top: 360px">Sie besitzen nicht die benötigten Berechtigungen zum Erzeugen von TeleTAN.</div>
<form action="/cwa/teletan" method="post">
<input class="button" style="top: 360px;" type="submit" value="Eine TeleTAN erzeugen"/>
<input th:if="${role_test}" class="button" style="top: 360px;" type="submit" th:name="${'TEST'}" value="Eine TeleTAN (positiver PCR Test) erzeugen" />
<input th:if="${role_event}" class="button" style="top: 420px;" type="submit" th:name="${'EVENT'}" value="Eine TeleTAN (Positiver bei Event) erzeugen" />
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
</form>

Expand Down
3 changes: 2 additions & 1 deletion src/main/resources/templates/teletan.html
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@
<div class="text" style="top: 300px;">Die neue TeleTAN lautet</div>
<div class="text-bold" style="top: 340px;" th:text="${teleTAN}"/>
<form action="/cwa/teletan" method="post">
<input class="button" style="top: 410px;" type="submit" value="Eine weitere TeleTAN erzeugen"/>
<input th:if="${role_test}" class="button" style="top: 410px;" type="submit" th:name="${'TEST'}" value="Eine weitere TeleTAN (positiver PCR Test) erzeugen" />
<input th:if="${role_event}" class="button" style="top: 490px;" type="submit" th:name="${'EVENT'}" value="Eine weitere TeleTAN (Positiver bei Event) erzeugen" />
<input type="hidden" th:name="${_csrf.parameterName}" th:value="${_csrf.token}" />
</form>

Expand Down
Loading