Taiga#458: fixing exception with real JWT from HS Keycloak OIDC (#220)
Co-authored-by: Michael Hoennig <michael@hoennig.de> Reviewed-on: https://dev.hostsharing.net/hostsharing/hs.hsadmin.ng/pulls/220 Reviewed-by: Marc Sandlus <hsh-marcsandlus@noreply.dev.hostsharing.net> Co-authored-by: Michael Hoennig <michael.hoennig@hostsharing.net> Co-committed-by: Michael Hoennig <michael.hoennig@hostsharing.net>
This commit is contained in:
committed by
Timotheus Pokorra
parent
28eebbc95a
commit
a1bac0f764
@@ -14,12 +14,18 @@ import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoder;
|
||||
import org.springframework.security.oauth2.jwt.JwtDecoders;
|
||||
import org.springframework.security.oauth2.jose.jws.MacAlgorithm;
|
||||
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder;
|
||||
import org.springframework.security.web.SecurityFilterChain;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import javax.crypto.spec.SecretKeySpec;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
import static net.hostsharing.hsadminng.config.JwtFakeBearer.RSA_KEY;
|
||||
|
||||
@@ -63,13 +69,25 @@ public abstract class BaseWebSecurityConfig {
|
||||
.build();
|
||||
}
|
||||
|
||||
@Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri:http://localhost:${server.port}/fake-jwt/.well-known/jwks.json}")
|
||||
private String jwkSetUri;
|
||||
|
||||
@Bean
|
||||
@Profile("!fake-jwt")
|
||||
public JwtDecoder jwtDecoder() {
|
||||
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
|
||||
public JwtDecoder jwtDecoder(
|
||||
// FIXME: Maybe move all defaults from the application.yml to here?
|
||||
@Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri:}") final String issuerUri,
|
||||
@Value("${spring.security.oauth2.resourceserver.jwt.jwk-set-uri:}") final String jwkSetUri,
|
||||
@Value("${spring.security.oauth2.resourceserver.jwt.hmac-secret:${HSADMINNG_JWT_HMAC_SECRET:}}") final String hmacSecret) {
|
||||
if (StringUtils.hasText(hmacSecret)) {
|
||||
return NimbusJwtDecoder.withSecretKey(new SecretKeySpec(hmacSecret.getBytes(StandardCharsets.UTF_8), "HmacSHA512"))
|
||||
.macAlgorithm(MacAlgorithm.HS512)
|
||||
.build();
|
||||
}
|
||||
if (StringUtils.hasText(jwkSetUri)) {
|
||||
return NimbusJwtDecoder.withJwkSetUri(jwkSetUri).build();
|
||||
}
|
||||
if (StringUtils.hasText(issuerUri)) {
|
||||
return JwtDecoders.fromIssuerLocation(issuerUri);
|
||||
}
|
||||
throw new IllegalStateException("Either spring.security.oauth2.resourceserver.jwt.hmac-secret (HSADMINNG_JWT_HMAC_SECRET), spring.security.oauth2.resourceserver.jwt.jwk-set-uri (HSADMINNG_JWT_JWKS_URL) or ...issuer-uri (HSADMINNG_JWT_ISSUER) must be configured.");
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
@@ -6,6 +6,7 @@ import lombok.val;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.core.context.SecurityContextHolder;
|
||||
import org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationToken;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
@@ -47,7 +48,17 @@ public class Context {
|
||||
|
||||
@Transactional(propagation = MANDATORY)
|
||||
public void define() {
|
||||
define(SecurityContextHolder.getContext().getAuthentication().getName(), null);
|
||||
val auth = SecurityContextHolder.getContext().getAuthentication();
|
||||
// FIXME: this code works for simplified JWT in tests as well as the real Keycloak, but there should be only one way
|
||||
// if "preferred_username" is set, use it, otherwise use "sub"
|
||||
val username = Optional.of(auth)
|
||||
.filter(JwtAuthenticationToken.class::isInstance)
|
||||
.map(JwtAuthenticationToken.class::cast)
|
||||
.map(JwtAuthenticationToken::getToken)
|
||||
.map(token -> token.getClaimAsString("preferred_username"))
|
||||
.filter(claim -> !claim.isBlank()) // force to getName ("sub") if blank
|
||||
.orElseGet(auth::getName);
|
||||
define(username, null);
|
||||
}
|
||||
|
||||
@Transactional(propagation = MANDATORY)
|
||||
|
||||
Reference in New Issue
Block a user