From 5e50dd92a10e25b0a2bedffb8f93822cc8706395 Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen <46576810+jolarsen@users.noreply.github.com> Date: Mon, 14 Oct 2024 12:41:12 +0200 Subject: [PATCH] Eksponere innkommende token-OID, logge rest-STS (#1385) * Eksponere innkommende token-OID, logge rest-STS * Getter for oid --- .../sikkerhet/abac/KontekstTokenProvider.java | 3 +- .../jaxrs/AuthenticationFilterDelegate.java | 11 ++++--- .../nav/vedtak/sikkerhet/kontekst/Groups.java | 5 ++- .../sikkerhet/kontekst/GroupsProvider.java | 3 +- .../sikkerhet/kontekst/RequestKontekst.java | 13 ++++++-- .../kontekst/RequestKontekstProvider.java | 6 ++++ .../oidc/validator/OidcTokenValidator.java | 32 +++++++++++++++---- .../validator/OidcTokenValidatorResult.java | 13 ++++---- .../validator/OidcTokenValidatorTest.java | 11 ++++++- 9 files changed, 72 insertions(+), 25 deletions(-) diff --git a/felles/abac-kontekst/src/main/java/no/nav/foreldrepenger/sikkerhet/abac/KontekstTokenProvider.java b/felles/abac-kontekst/src/main/java/no/nav/foreldrepenger/sikkerhet/abac/KontekstTokenProvider.java index 7104d38ec..abf8fdb67 100644 --- a/felles/abac-kontekst/src/main/java/no/nav/foreldrepenger/sikkerhet/abac/KontekstTokenProvider.java +++ b/felles/abac-kontekst/src/main/java/no/nav/foreldrepenger/sikkerhet/abac/KontekstTokenProvider.java @@ -25,7 +25,6 @@ public IdentType getIdentType() { @Override public OpenIDToken openIdToken() { - var kontekst = PROVIDER.getKontekst(); - return kontekst instanceof RequestKontekst rk ? rk.getToken() : null; + return PROVIDER.getToken(); } } diff --git a/felles/auth-filter/src/main/java/no/nav/vedtak/sikkerhet/jaxrs/AuthenticationFilterDelegate.java b/felles/auth-filter/src/main/java/no/nav/vedtak/sikkerhet/jaxrs/AuthenticationFilterDelegate.java index 21ae03a92..e99132d67 100644 --- a/felles/auth-filter/src/main/java/no/nav/vedtak/sikkerhet/jaxrs/AuthenticationFilterDelegate.java +++ b/felles/auth-filter/src/main/java/no/nav/vedtak/sikkerhet/jaxrs/AuthenticationFilterDelegate.java @@ -4,7 +4,6 @@ import java.lang.reflect.Method; import java.time.Instant; import java.util.Optional; -import java.util.function.Function; import java.util.function.Supplier; import jakarta.ws.rs.WebApplicationException; @@ -127,8 +126,12 @@ public static void validerTokenSetKontekst(ResourceInfo resourceInfo, TokenStrin var expiresAt = Optional.ofNullable(JwtUtil.getExpirationTime(claims)).orElseGet(() -> Instant.now().plusSeconds(300)); var token = new OpenIDToken(configuration.type(), OpenIDToken.OIDC_DEFAULT_TOKEN_TYPE, tokenString, null, expiresAt.toEpochMilli()); - if (OpenIDProvider.STS.equals(configuration.type()) && getAnnotation(resourceInfo, TillatSTS.class).isEmpty()) { - throw new ValideringsFeil("Kall med STS til endepunkt som ikke eksplisitt tillater STS"); + if (OpenIDProvider.STS.equals(configuration.type())) { + if (getAnnotation(resourceInfo, TillatSTS.class).isEmpty()) { + throw new ValideringsFeil("Kall med STS til endepunkt som ikke eksplisitt tillater STS"); + } else { + LOG.info("Innkommende STS - metode {} har annotering TillatSTS", resourceInfo.getResourceMethod().getName()); + } } // Valider @@ -138,7 +141,7 @@ public static void validerTokenSetKontekst(ResourceInfo resourceInfo, TokenStrin // Håndter valideringsresultat if (validateResult.isValid()) { KontekstHolder.setKontekst(RequestKontekst.forRequest(validateResult.subject(), validateResult.compactSubject(), - validateResult.identType(), token, validateResult.getGrupper())); + validateResult.identType(), token, validateResult.oid(), validateResult.getGrupper())); LOG.trace("token validert"); } else { throw new ValideringsFeil("Ugyldig token"); diff --git a/felles/kontekst/src/main/java/no/nav/vedtak/sikkerhet/kontekst/Groups.java b/felles/kontekst/src/main/java/no/nav/vedtak/sikkerhet/kontekst/Groups.java index cb17e363e..9dc42e961 100644 --- a/felles/kontekst/src/main/java/no/nav/vedtak/sikkerhet/kontekst/Groups.java +++ b/felles/kontekst/src/main/java/no/nav/vedtak/sikkerhet/kontekst/Groups.java @@ -6,5 +6,8 @@ public enum Groups { OVERSTYRER, OPPGAVESTYRER, VEILEDER, - DRIFT + DRIFT, + FORTROLIG, + STRENGTFORTROLIG, + SKJERMET } diff --git a/felles/kontekst/src/main/java/no/nav/vedtak/sikkerhet/kontekst/GroupsProvider.java b/felles/kontekst/src/main/java/no/nav/vedtak/sikkerhet/kontekst/GroupsProvider.java index 5e4f8c57a..49c9372d1 100644 --- a/felles/kontekst/src/main/java/no/nav/vedtak/sikkerhet/kontekst/GroupsProvider.java +++ b/felles/kontekst/src/main/java/no/nav/vedtak/sikkerhet/kontekst/GroupsProvider.java @@ -19,7 +19,6 @@ public class GroupsProvider { private static final Logger LOG = LoggerFactory.getLogger(GroupsProvider.class); private static final String SUFFIX = ".properties"; - private static final String PREFIX = "groups"; private static GroupsProvider INSTANCE; @@ -88,7 +87,7 @@ private static String getInfix() { if (cluster.isLocal()) { return "-vtp"; } - return "-" + (cluster.isProd() ? "prod" : "dev"); + return cluster.isProd() ? "-prod" : "-dev"; } } diff --git a/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/kontekst/RequestKontekst.java b/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/kontekst/RequestKontekst.java index a48bcd7ad..f90450236 100644 --- a/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/kontekst/RequestKontekst.java +++ b/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/kontekst/RequestKontekst.java @@ -3,6 +3,7 @@ import java.util.HashSet; import java.util.Optional; import java.util.Set; +import java.util.UUID; import no.nav.vedtak.log.mdc.MDCOperations; import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken; @@ -10,23 +11,29 @@ public final class RequestKontekst extends BasisKontekst { private final OpenIDToken token; + private UUID oid; private final Set grupper; - private RequestKontekst(String uid, String kompaktUid, IdentType identType, String consumerId, OpenIDToken token, Set grupper) { + private RequestKontekst(String uid, String kompaktUid, IdentType identType, String consumerId, OpenIDToken token, UUID oid, Set grupper) { super(SikkerhetContext.REQUEST, uid, kompaktUid, identType, consumerId); this.token = token; + this.oid = oid; this.grupper = new HashSet<>(grupper); } - public static RequestKontekst forRequest(String uid, String kompaktUid, IdentType identType, OpenIDToken token, Set grupper) { + public static RequestKontekst forRequest(String uid, String kompaktUid, IdentType identType, OpenIDToken token, UUID oid, Set grupper) { var konsumentId = Optional.ofNullable(MDCOperations.getConsumerId()).orElse(uid); - return new RequestKontekst(uid, kompaktUid, identType, konsumentId, token, grupper); + return new RequestKontekst(uid, kompaktUid, identType, konsumentId, token, oid, grupper); } public OpenIDToken getToken() { return token; } + public UUID getOid() { + return oid; + } + public Set getGrupper() { return grupper; } diff --git a/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/kontekst/RequestKontekstProvider.java b/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/kontekst/RequestKontekstProvider.java index 4b0952c1c..f1a883c09 100644 --- a/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/kontekst/RequestKontekstProvider.java +++ b/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/kontekst/RequestKontekstProvider.java @@ -2,10 +2,16 @@ import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken; +import java.util.UUID; + public interface RequestKontekstProvider extends KontekstProvider { default OpenIDToken getToken() { return getKontekst() instanceof RequestKontekst tk ? tk.getToken() : null; } + default UUID getOid() { + return getKontekst() instanceof RequestKontekst tk ? tk.getOid() : null; + } + } diff --git a/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidator.java b/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidator.java index 72240ca51..22e4c2443 100644 --- a/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidator.java +++ b/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidator.java @@ -1,16 +1,21 @@ package no.nav.vedtak.sikkerhet.oidc.validator; +import static no.nav.vedtak.sikkerhet.oidc.validator.ConsumerMetric.registrer; + import java.security.Key; import java.util.List; import java.util.Objects; import java.util.Optional; import java.util.Set; +import java.util.UUID; import org.jose4j.jwt.JwtClaims; import org.jose4j.jwt.consumer.InvalidJwtException; import org.jose4j.jwt.consumer.JwtConsumer; import org.jose4j.jwt.consumer.JwtConsumerBuilder; import org.jose4j.jwx.JsonWebStructure; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import no.nav.vedtak.sikkerhet.kontekst.GroupsProvider; import no.nav.vedtak.sikkerhet.kontekst.IdentType; @@ -22,10 +27,10 @@ import no.nav.vedtak.sikkerhet.oidc.jwks.JwtHeader; import no.nav.vedtak.sikkerhet.oidc.token.TokenString; -import static no.nav.vedtak.sikkerhet.oidc.validator.ConsumerMetric.registrer; - public class OidcTokenValidator { + private static final Logger LOG = LoggerFactory.getLogger(OidcTokenValidator.class); + private static final Set AUTHENTICATION_LEVEL_ID_PORTEN = Set.of("Level4", "idporten-loa-high"); // Level4 er gammel og utgår ila 2023 // Misc claims and values - ikke nais-spesifikke @@ -149,7 +154,8 @@ private String validateClaims(JwtClaims claims) { } private OidcTokenValidatorResult validateAzure(JwtClaims claims, String subject) { - if (isAzureClientCredentials(claims, subject)) { + var oid = getAzureOid(claims); + if (isAzureClientCredentials(claims, subject, oid)) { var brukSubject = Optional.ofNullable(JwtUtil.getStringClaim(claims, AzureProperty.AZP_NAME)).orElse(subject); registrer(clientName, brukSubject, OpenIDProvider.AZUREAD, IdentType.Systemressurs); // Ta med bakoverkompatibelt navn ettersom azp_name er ganske langt (tabeller / opprettet_av) @@ -169,16 +175,30 @@ private OidcTokenValidatorResult validateAzure(JwtClaims claims, String subject) var grupper = Optional.ofNullable(JwtUtil.getStringListClaim(claims, AzureProperty.GRUPPER)) .map(arr -> GroupsProvider.instance().getGroupsFrom(arr)) .orElse(Set.of()); - return OidcTokenValidatorResult.valid(brukSubject, IdentType.InternBruker, grupper, JwtUtil.getExpirationTimeRaw(claims)); + return OidcTokenValidatorResult.valid(brukSubject, IdentType.InternBruker, oid, grupper, JwtUtil.getExpirationTimeRaw(claims)); } } // Sjekker både gammel konvensjon (oid=sub) og nyere (idtyp="app") - private boolean isAzureClientCredentials(JwtClaims claims, String subject) { - return Objects.equals(subject, JwtUtil.getStringClaim(claims, OID)) || + private boolean isAzureClientCredentials(JwtClaims claims, String subject, UUID oid) { + return Objects.equals(subject, Optional.ofNullable(oid).map(UUID::toString).orElse(null)) || Objects.equals(APP, JwtUtil.getStringClaim(claims, IDTYP)); } + private UUID getAzureOid(JwtClaims claims) { + var oid = JwtUtil.getStringClaim(claims, OID); + if (oid == null) { + LOG.info("AZURE VALIDATE oid er null"); + return null; + } + try { + return UUID.fromString(oid); + } catch (Exception e) { + LOG.info("AZURE VALIDATE kunne ikke konvertere oid til UUID {}", oid); + return null; + } + } + private OidcTokenValidatorResult validateTokenX(JwtClaims claims, String subject) { var acrClaim = JwtUtil.getStringClaim(claims, ACR); var level4 = Optional.ofNullable(acrClaim) diff --git a/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidatorResult.java b/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidatorResult.java index cf89a714f..dce841e40 100644 --- a/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidatorResult.java +++ b/felles/oidc/src/main/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidatorResult.java @@ -1,29 +1,30 @@ package no.nav.vedtak.sikkerhet.oidc.validator; import java.util.Set; +import java.util.UUID; import no.nav.vedtak.sikkerhet.kontekst.Groups; import no.nav.vedtak.sikkerhet.kontekst.IdentType; public record OidcTokenValidatorResult(boolean isValid, String errorMessage, String subject, IdentType identType, - String compactSubject, Set grupper, long expSeconds) { + String compactSubject, UUID oid, Set grupper, long expSeconds) { private static final String NO_CLAIMS = "Can't get claims from an invalid token"; public static OidcTokenValidatorResult invalid(String errorMessage) { - return new OidcTokenValidatorResult(false, errorMessage, null, null, null, Set.of(), 0); + return new OidcTokenValidatorResult(false, errorMessage, null, null, null, null, Set.of(), 0); } public static OidcTokenValidatorResult valid(String subject, IdentType identType, long expSeconds) { - return new OidcTokenValidatorResult(true, null, subject, identType, subject, Set.of(), expSeconds); + return new OidcTokenValidatorResult(true, null, subject, identType, subject, null, Set.of(), expSeconds); } - public static OidcTokenValidatorResult valid(String subject, IdentType identType, Set grupper, long expSeconds) { - return new OidcTokenValidatorResult(true, null, subject, identType, subject, grupper, expSeconds); + public static OidcTokenValidatorResult valid(String subject, IdentType identType, UUID oid, Set grupper, long expSeconds) { + return new OidcTokenValidatorResult(true, null, subject, identType, subject, oid, grupper, expSeconds); } public static OidcTokenValidatorResult valid(String subject, IdentType identType, String compactSubject, long expSeconds) { - return new OidcTokenValidatorResult(true, null, subject, identType, compactSubject, Set.of(), expSeconds); + return new OidcTokenValidatorResult(true, null, subject, identType, compactSubject, null, Set.of(), expSeconds); } diff --git a/felles/oidc/src/test/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidatorTest.java b/felles/oidc/src/test/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidatorTest.java index 9e55398ae..0b56fc60b 100644 --- a/felles/oidc/src/test/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidatorTest.java +++ b/felles/oidc/src/test/java/no/nav/vedtak/sikkerhet/oidc/validator/OidcTokenValidatorTest.java @@ -8,6 +8,7 @@ import java.util.Arrays; import java.util.Base64; import java.util.List; +import java.util.UUID; import org.jose4j.jwt.NumericDate; import org.junit.jupiter.api.AfterEach; @@ -133,7 +134,9 @@ void skal_ekstrahere_kortnavn_fra_aad_client_credentials_med_azpname() { var langClientId = "klusternavn:langtnamespace:applikasjon"; - var token = new OidcTokenGenerator().withClaim(AzureProperty.AZP_NAME, langClientId).withClaim("oid", "demo") // samme som sub for CC + var token = new OidcTokenGenerator().withClaim(AzureProperty.AZP_NAME, langClientId) + .withClaim("idtyp", "app") + .withClaim("oid", UUID.randomUUID().toString()) // samme som sub for CC .createHeaderTokenHolder(); var result = tokenValidator.validate(token); @@ -150,14 +153,17 @@ void skal_ekstrahere_ansattnavn_fra_aad_obo_med_navident_uten_grupper() { // that its client_id is the Claim Value var ident = "minident"; + var oid = UUID.randomUUID(); var token = new OidcTokenGenerator() .withClaim(AzureProperty.NAV_IDENT, ident) + .withClaim("oid", oid.toString()) .createHeaderTokenHolder(); OidcTokenValidatorResult result = tokenValidator.validate(token); assertValid(result); assertThat(result.getSubject()).isEqualTo(ident); + assertThat(result.oid()).isEqualTo(oid); assertThat(result.grupper()).isEmpty(); assertThat(result.getCompactSubject()).isEqualTo(ident); } @@ -171,15 +177,18 @@ void skal_ekstrahere_grupper_fra_aad_obo_med_navident_med_grupper() { var ident = "minident"; var grupper = List.of("saksbehandler", "oppgavestyrer"); + var oid = UUID.randomUUID(); var token = new OidcTokenGenerator() .withClaim(AzureProperty.NAV_IDENT, ident) .withGroupsClam(AzureProperty.GRUPPER, grupper) + .withClaim("oid", oid.toString()) .createHeaderTokenHolder(); OidcTokenValidatorResult result = tokenValidator.validate(token); assertValid(result); assertThat(result.getSubject()).isEqualTo(ident); + assertThat(result.oid()).isEqualTo(oid); assertThat(result.grupper()).containsAll(List.of(Groups.SAKSBEHANDLER, Groups.OPPGAVESTYRER)); assertThat(result.getCompactSubject()).isEqualTo(ident); }