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

Commit

Permalink
Feat: UI controls for Event TeleTan (#111)
Browse files Browse the repository at this point in the history
* Add UI controls for Event TeleTan

* changed log to persist type

Co-authored-by: m.schulte <M.Schulte@t-systems.com>
  • Loading branch information
f11h and mschulte-tsi committed Aug 19, 2021
1 parent 4d097c0 commit 2412501
Show file tree
Hide file tree
Showing 8 changed files with 244 additions and 71 deletions.
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

0 comments on commit 2412501

Please sign in to comment.