Skip to content

Commit

Permalink
Eksponere innkommende token-OID, logge rest-STS (#1385)
Browse files Browse the repository at this point in the history
* Eksponere innkommende token-OID, logge rest-STS

* Getter for oid
  • Loading branch information
jolarsen authored Oct 14, 2024
1 parent 3c5b8a3 commit 5e50dd9
Show file tree
Hide file tree
Showing 9 changed files with 72 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -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");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,8 @@ public enum Groups {
OVERSTYRER,
OPPGAVESTYRER,
VEILEDER,
DRIFT
DRIFT,
FORTROLIG,
STRENGTFORTROLIG,
SKJERMET
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -88,7 +87,7 @@ private static String getInfix() {
if (cluster.isLocal()) {
return "-vtp";
}
return "-" + (cluster.isProd() ? "prod" : "dev");
return cluster.isProd() ? "-prod" : "-dev";
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -3,30 +3,37 @@
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;

public final class RequestKontekst extends BasisKontekst {

private final OpenIDToken token;
private UUID oid;
private final Set<Groups> grupper;

private RequestKontekst(String uid, String kompaktUid, IdentType identType, String consumerId, OpenIDToken token, Set<Groups> grupper) {
private RequestKontekst(String uid, String kompaktUid, IdentType identType, String consumerId, OpenIDToken token, UUID oid, Set<Groups> 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<Groups> grupper) {
public static RequestKontekst forRequest(String uid, String kompaktUid, IdentType identType, OpenIDToken token, UUID oid, Set<Groups> 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<Groups> getGrupper() {
return grupper;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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<String> 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
Expand Down Expand Up @@ -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)
Expand All @@ -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)
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Groups> grupper, long expSeconds) {
String compactSubject, UUID oid, Set<Groups> 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<Groups> grupper, long expSeconds) {
return new OidcTokenValidatorResult(true, null, subject, identType, subject, grupper, expSeconds);
public static OidcTokenValidatorResult valid(String subject, IdentType identType, UUID oid, Set<Groups> 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);
}


Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand All @@ -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);
}
Expand Down

0 comments on commit 5e50dd9

Please sign in to comment.