Fixing API access through external APPs

This commit is contained in:
Jan 2025-10-30 21:36:10 +01:00
parent d06aa74029
commit f62cfbfb66
4 changed files with 57 additions and 19 deletions

View file

@ -47,10 +47,7 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.OncePerRequestFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.*;
import java.util.function.Supplier;
@ -65,6 +62,7 @@ public class SecurityConfig {
@Value("${lcc.allowed_oauth_token_cors:*}") // Default: alle Origins
private String oauthTokenCors;
@Bean
@Profile("!dev & !test") // Only active when NOT in dev profile
public SecurityFilterChain prodSecurityFilterChain(HttpSecurity http, JwtTokenService jwtTokenService) throws Exception {
@ -251,7 +249,25 @@ public class SecurityConfig {
User user = null;
String workdayId = oidcUser.getAttribute("workday_id");
String workdayId = oidcUser.getAttribute("employeeid");
if (workdayId == null) {
workdayId = oidcUser.getAttribute("extension_WorkdayID");
}
if (workdayId == null) {
workdayId = oidcUser.getAttribute("workdayWorkerID");
}
if (workdayId == null) {
workdayId = oidcUser.getAttribute("onpremisesimmutableid");
}
if (workdayId == null) {
// Check for any extension attribute containing "workday"
Map<String, Object> claims = oidcUser.getIdToken().getClaims();
workdayId = claims.entrySet().stream()
.filter(e -> e.getKey().toLowerCase().contains("workday"))
.map(e -> String.valueOf(e.getValue()))
.findFirst()
.orElse(null);
}
// Try different ways to get email
String email = oidcUser.getEmail();
@ -269,7 +285,7 @@ public class SecurityConfig {
if (workdayId != null) {
user = userRepository.getByWorkdayId(workdayId);
if (user != null) {
user.getGroups().forEach(group -> mappedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + group.getName())));
user.getGroups().forEach(group -> mappedAuthorities.add(new SimpleGrantedAuthority("ROLE_" + group.getName().toUpperCase())));
userId = user.getId();
}
} else if (email != null) {
@ -311,15 +327,15 @@ public class SecurityConfig {
Claims claims = jwtTokenService.parseClaimsWithoutValidation(token);
String tokenType = claims.get("token_type", String.class);
if ("ext_app".equals(tokenType)) {
return null; // using the SelfIssuedJwtFilter
return null;
}
} catch (Exception e) {
// carry on ...
log.debug("Failed to parse token without validation", e);
}
return token; // some other token
return token;
}
return null; // all other requests
return null;
};
}
@ -345,9 +361,12 @@ public class SecurityConfig {
@Override
protected void doFilterInternal(HttpServletRequest request, @NotNull HttpServletResponse response,
@NotNull FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrfToken != null) {
csrfToken.getToken();
// Skip CSRF cookie for token endpoint
if (!request.getRequestURI().startsWith("/oauth2/token")) {
CsrfToken csrfToken = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrfToken != null) {
csrfToken.getToken();
}
}
filterChain.doFilter(request, response);
}

View file

@ -30,6 +30,11 @@ public class SelfIssuedJwtFilter extends OncePerRequestFilter {
@NotNull FilterChain filterChain)
throws ServletException, IOException {
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
filterChain.doFilter(request, response);
return;
}
String token = extractToken(request);
if (token != null && isSelfIssuedToken(token)) {

View file

@ -33,7 +33,7 @@ public class GroupController {
* @return A ResponseEntity containing the list of groups and pagination headers.
*/
@GetMapping({"/", ""})
@PreAuthorize("hasAnyRole('RIGHT-MANAGMENT', 'SERVICE')")
@PreAuthorize("hasAnyRole('RIGHT-MANAGEMENT', 'SERVICE')")
public ResponseEntity<List<GroupDTO>> listGroups(@RequestParam(defaultValue = "20") @Min(1) int limit,
@RequestParam(defaultValue = "1") @Min(1) int page) {

View file

@ -41,11 +41,25 @@ public class JwtTokenService {
}
public Claims parseClaimsWithoutValidation(String token) {
return Jwts.parser()
.unsecured()
.build()
.parseUnsecuredClaims(token)
.getPayload();
try {
String[] parts = token.split("\\.");
String payload = parts[1];
byte[] decodedBytes = java.util.Base64.getUrlDecoder().decode(payload);
String decodedPayload = new String(decodedBytes, StandardCharsets.UTF_8);
com.fasterxml.jackson.databind.ObjectMapper mapper =
new com.fasterxml.jackson.databind.ObjectMapper();
@SuppressWarnings("unchecked")
java.util.Map<String, Object> claimsMap =
mapper.readValue(decodedPayload, java.util.Map.class);
return Jwts.claims().add(claimsMap).build();
} catch (Exception e) {
throw new IllegalArgumentException("Failed to parse JWT claims", e);
}
}
public Claims validateToken(String token) {