Skip to content

Commit

Permalink
Sanere støtte for innkommende STS (#1387)
Browse files Browse the repository at this point in the history
* Sanere støtte for innkommende STS

* Feedback og mer rydding

* Fjerne all bruk av Systembruker utenom ABAC

* Litt mer rydding

---------

Co-authored-by: Michal J. Sladek <mrsladek@users.noreply.github.com>
  • Loading branch information
jolarsen and mrsladek authored Oct 18, 2024
1 parent 535eadb commit 5a0bb6e
Show file tree
Hide file tree
Showing 21 changed files with 61 additions and 325 deletions.
2 changes: 1 addition & 1 deletion felles/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Felles biblioteker, som dekker
# Feilhåndtering
standard for exceptions, logfeilmeldinger, feilmelding koder
# Sikkerhet
OIDC Autentisering, Azure + STS - Security Token Service for veksling av tokens, ABAC (PEP/PDP)
OIDC Autentisering, Azure + TokenX tokens, ABAC (PEP/PDP)
# Database oppsett/tillegg
* Støtter JPA ORM XML konfigurasjon i flere filer (auto-discovery). Gjør det mulig å dele opp datamodellen i ulike moduler.
* Støtter for tilgang til flere skjemaer gjennom samme datasource (uten å hardkode schema navn i hibernate). Gjør det mulig å dele opp database i flere skjemaer
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,17 @@
import java.util.Collection;
import java.util.Optional;

import org.jboss.weld.interceptor.util.proxy.TargetInstanceProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import jakarta.annotation.Priority;
import jakarta.enterprise.context.Dependent;
import jakarta.inject.Inject;
import jakarta.interceptor.AroundInvoke;
import jakarta.interceptor.Interceptor;
import jakarta.interceptor.InvocationContext;

import org.jboss.weld.interceptor.util.proxy.TargetInstanceProxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import no.nav.foreldrepenger.konfig.Environment;
import no.nav.vedtak.exception.TekniskException;
import no.nav.vedtak.sikkerhet.abac.beskyttet.ActionType;
Expand Down Expand Up @@ -84,8 +85,8 @@ private boolean erSystembrukerKall(BeskyttetRessursAttributter beskyttetRessursA
return Optional.ofNullable(beskyttetRessursAttributter)
.map(BeskyttetRessursAttributter::getToken)
.map(Token::getIdentType)
.orElse(IdentType.InternBruker)
.erSystem();
.filter(IdentType::erSystem)
.isPresent();
}

private BeskyttetRessursAttributter hentBeskyttetRessursAttributter(InvocationContext invocationContext, AbacDataAttributter dataAttributter) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ protected Tilgangsbeslutning vurderLokalTilgang(BeskyttetRessursAttributter besk
}

// AzureAD CC kommer med sub som ikke ikke en bruker med vanlige AD-grupper og roller
// Token kan utvides med roles og groups - men oppsettet er langt fra det som er kjent fra STS mv.
// Token kan utvides med roles og groups
// Kan legge inn filter på claims/roles intern og/eller ekstern.
private boolean kanForetaLokalTilgangsbeslutning(Token token) {
var identType = token.getIdentType();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public IdentType getIdentType() {

private static TokenType utledTokenType(OpenIDToken token) {
return switch (token.provider()) {
case STS, AZUREAD -> TokenType.OIDC;
case AZUREAD -> TokenType.OIDC;
case TOKENX -> TokenType.TOKENX;
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ public interface TokenProvider {
IdentType getIdentType();

/**
* OIDC tokenet til brukeren. Helst fra følgende providere: TokenX, AzureAD, STS.
* OIDC tokenet til brukeren. Helst fra følgende providere: TokenX, AzureAD.
* Sendes til PDP (Policy Decision Point) og gir informasjon til ABAC om subject og auth level.
*
* @return bruker OIDC token.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;
import static org.mockito.internal.verification.VerificationModeFactory.times;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
Expand Down Expand Up @@ -138,19 +137,6 @@ void skal_gi_tilgang_for_godkjent_ekstern_azure_cc() {
verifyNoInteractions(pdpKlientMock);
}

@Test
void skal_sjekke_mot_abac_hvis_sts_systembruker() {
var token = new OpenIDToken(OpenIDProvider.STS, new TokenString("token"));
when(tokenProvider.getUid()).thenReturn("srvTestbruker");
var attributter = lagBeskyttetRessursAttributterAzure(AvailabilityType.ALL, token, "srvTestbruker", IdentType.Systemressurs);

when(pdpRequestBuilder.abacDomene()).thenReturn("domene");
when(pdpRequestBuilder.lagAppRessursData(any())).thenReturn(AppRessursData.builder().build());

pep.vurderTilgang(attributter);
verify(pdpKlientMock, times(1)).forespørTilgang(eq(attributter), eq("domene"), any());
}

@Test
void skal_kalle_pdp_for_annet_enn_pip_tjenester() {
when(tokenProvider.getUid()).thenReturn("z142443");
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
package no.nav.vedtak.sikkerhet.abac.internal;

import no.nav.vedtak.exception.ManglerTilgangException;
import no.nav.vedtak.log.audit.Auditdata;
import no.nav.vedtak.log.audit.Auditlogger;
import no.nav.vedtak.sikkerhet.abac.*;
import no.nav.vedtak.sikkerhet.abac.beskyttet.ActionType;
import no.nav.vedtak.sikkerhet.abac.pdp.AppRessursData;
import no.nav.vedtak.sikkerhet.oidc.config.OpenIDProvider;
import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken;
import no.nav.vedtak.sikkerhet.oidc.token.TokenString;
import static no.nav.vedtak.sikkerhet.abac.policy.ForeldrepengerAttributter.RESOURCE_TYPE_INTERNAL_PIP;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.regex.Pattern;

import jakarta.interceptor.InvocationContext;
import jakarta.ws.rs.Path;

import org.assertj.core.api.Fail;
import org.junit.jupiter.api.Test;
Expand All @@ -18,17 +23,23 @@
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;

import jakarta.interceptor.InvocationContext;
import jakarta.ws.rs.Path;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.regex.Pattern;

import static no.nav.vedtak.sikkerhet.abac.policy.ForeldrepengerAttributter.RESOURCE_TYPE_INTERNAL_PIP;
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;
import no.nav.vedtak.exception.ManglerTilgangException;
import no.nav.vedtak.log.audit.Auditdata;
import no.nav.vedtak.log.audit.Auditlogger;
import no.nav.vedtak.sikkerhet.abac.AbacAuditlogger;
import no.nav.vedtak.sikkerhet.abac.AbacDataAttributter;
import no.nav.vedtak.sikkerhet.abac.AbacDto;
import no.nav.vedtak.sikkerhet.abac.AbacResultat;
import no.nav.vedtak.sikkerhet.abac.BeskyttetRessurs;
import no.nav.vedtak.sikkerhet.abac.BeskyttetRessursInterceptor;
import no.nav.vedtak.sikkerhet.abac.StandardAbacAttributtType;
import no.nav.vedtak.sikkerhet.abac.Tilgangsbeslutning;
import no.nav.vedtak.sikkerhet.abac.TokenProvider;
import no.nav.vedtak.sikkerhet.abac.beskyttet.ActionType;
import no.nav.vedtak.sikkerhet.abac.pdp.AppRessursData;
import no.nav.vedtak.sikkerhet.oidc.config.OpenIDProvider;
import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken;
import no.nav.vedtak.sikkerhet.oidc.token.TokenString;

@ExtendWith(MockitoExtension.class)
public class BeskyttetRessursInterceptorTest {
Expand All @@ -41,7 +52,7 @@ public class BeskyttetRessursInterceptorTest {

private final ArgumentCaptor<Auditdata> auditdataCaptor = ArgumentCaptor.forClass(Auditdata.class);

public static final OpenIDToken DUMMY_OPENID_TOKEN = new OpenIDToken(OpenIDProvider.STS, new TokenString(DUMMY_ID_TOKEN));
public static final OpenIDToken DUMMY_OPENID_TOKEN = new OpenIDToken(OpenIDProvider.AZUREAD, new TokenString(DUMMY_ID_TOKEN));

@Mock
private static TokenProvider tokenProvider;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@
class PdpKlientImplTest {

private static final String JWT_TOKENSTRING = "eyAidHlwIjogIkpXVCIsICJraWQiOiAiU0gxSWVSU2sxT1VGSDNzd1orRXVVcTE5VHZRPSIsICJhbGciOiAiUlMyNTYiIH0.eyAiYXRfaGFzaCI6ICIyb2c1RGk5ZW9LeFhOa3VPd0dvVUdBIiwgInN1YiI6ICJzMTQyNDQzIiwgImF1ZGl0VHJhY2tpbmdJZCI6ICI1NTM0ZmQ4ZS03MmE2LTRhMWQtOWU5YS1iZmEzYThhMTljMDUtNjE2NjA2NyIsICJpc3MiOiAiaHR0cHM6Ly9pc3NvLXQuYWRlby5ubzo0NDMvaXNzby9vYXV0aDIiLCAidG9rZW5OYW1lIjogImlkX3Rva2VuIiwgImF1ZCI6ICJPSURDIiwgImNfaGFzaCI6ICJiVWYzcU5CN3dTdi0wVlN0bjhXLURnIiwgIm9yZy5mb3JnZXJvY2sub3BlbmlkY29ubmVjdC5vcHMiOiAiMTdhOGZiMzYtMGI0Ny00YzRkLWE4YWYtZWM4Nzc3Y2MyZmIyIiwgImF6cCI6ICJPSURDIiwgImF1dGhfdGltZSI6IDE0OTgwMzk5MTQsICJyZWFsbSI6ICIvIiwgImV4cCI6IDE0OTgwNDM1MTUsICJ0b2tlblR5cGUiOiAiSldUVG9rZW4iLCAiaWF0IjogMTQ5ODAzOTkxNSB9.S2DKQweQWZIfjaAT2UP9_dxrK5zqpXj8IgtjDLt5PVfLYfZqpWGaX-ckXG0GlztDVBlRK4ylmIYacTmEAUV_bRa_qWKRNxF83SlQRgHDSiE82SGv5WHOGEcAxf2w_d50XsgA2KDBCyv0bFIp9bCiKzP11uWPW0v4uIkyw2xVxMVPMCuiMUtYFh80sMDf9T4FuQcFd0LxoYcSFDEDlwCdRiF3ufw73qtMYBlNIMbTGHx-DZWkZV7CgukmCee79gwQIvGwdLrgaDrHFCJUDCbB1FFEaE3p3_BZbj0T54fCvL69aHyWm1zEd9Pys15yZdSh3oSSr4yVNIxhoF-nQ7gY-g;";
public static final OpenIDToken JWT_TOKEN = new OpenIDToken(OpenIDProvider.STS, new TokenString(JWT_TOKENSTRING));
public static final OpenIDToken JWT_TOKEN = new OpenIDToken(OpenIDProvider.AZUREAD, new TokenString(JWT_TOKENSTRING));
public static final OpenIDToken JWT_TOKENX_TOKEN = new OpenIDToken(OpenIDProvider.TOKENX, new TokenString(JWT_TOKENSTRING));
private static final String DOMENE = "foreldrepenger";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@
import no.nav.vedtak.sikkerhet.kontekst.KontekstHolder;
import no.nav.vedtak.sikkerhet.kontekst.RequestKontekst;
import no.nav.vedtak.sikkerhet.oidc.config.ConfigProvider;
import no.nav.vedtak.sikkerhet.oidc.config.OpenIDProvider;
import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken;
import no.nav.vedtak.sikkerhet.oidc.token.TokenString;
import no.nav.vedtak.sikkerhet.oidc.validator.JwtUtil;
Expand Down Expand Up @@ -70,7 +69,7 @@ public static void validerSettKontekst(ResourceInfo resourceInfo, ContainerReque
LOG.trace("{} er whitelisted", metodenavn);
} else {
var tokenString = tokenfinder.get().orElseThrow(() -> new ValideringsFeil("Mangler token"));
validerTokenSetKontekst(resourceInfo, tokenString);
validerTokenSetKontekst(tokenString);
setUserAndConsumerId(KontekstHolder.getKontekst().getUid());
}
} catch (TekniskException | TokenFeil e) {
Expand Down Expand Up @@ -118,22 +117,14 @@ public static Optional<TokenString> getTokenFromHeader(ContainerRequestContext r
.map(TokenString::new);
}

public static void validerTokenSetKontekst(ResourceInfo resourceInfo, TokenString tokenString) {
private static void validerTokenSetKontekst(TokenString tokenString) {
// Sett opp OpenIDToken
var claims = JwtUtil.getClaims(tokenString.token());
var configuration = ConfigProvider.getOpenIDConfiguration(JwtUtil.getIssuer(claims))
.orElseThrow(() -> new TokenFeil("Token mangler issuer claim"));
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())) {
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
var tokenValidator = OidcTokenValidatorConfig.instance().getValidator(token.provider());
var validateResult = tokenValidator.validate(token.primary());
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ public void teardown() {
when(request.getHeaderString("Authorization")).thenReturn(OpenIDToken.OIDC_DEFAULT_TOKEN_TYPE + gyldigToken.token());

when(tokenValidator.validate(gyldigToken)).thenReturn(
OidcTokenValidatorResult.valid("demo", IdentType.utledIdentType("demo"), System.currentTimeMillis() / 1000 + 121));
OidcTokenValidatorResult.valid("demo", IdentType.InternBruker, System.currentTimeMillis() / 1000 + 121));

AuthenticationFilterDelegate.validerSettKontekst(ri, request);
assertThat(KontekstHolder.getKontekst().getContext()).isEqualTo(SikkerhetContext.REQUEST);
Expand All @@ -135,7 +135,7 @@ public void teardown() {

var gyldigToken = getGyldigToken();
when(request.getHeaderString("Authorization")).thenReturn(OpenIDToken.OIDC_DEFAULT_TOKEN_TYPE + gyldigToken.token());
when(tokenValidator.validate(gyldigToken)).thenReturn(OidcTokenValidatorResult.valid("demo", IdentType.utledIdentType("demo"),
when(tokenValidator.validate(gyldigToken)).thenReturn(OidcTokenValidatorResult.valid("demo", IdentType.InternBruker,
System.currentTimeMillis() / 1000 + sekunderGjenståendeGyldigTid));

AuthenticationFilterDelegate.validerSettKontekst(ri, request);
Expand All @@ -152,7 +152,7 @@ public void teardown() {

var gyldigToken = getGyldigToken();
when(request.getHeaderString("Authorization")).thenReturn(OpenIDToken.OIDC_DEFAULT_TOKEN_TYPE + gyldigToken.token());
when(tokenValidator.validate(gyldigToken)).thenReturn(OidcTokenValidatorResult.valid("demo", IdentType.utledIdentType("demo"),
when(tokenValidator.validate(gyldigToken)).thenReturn(OidcTokenValidatorResult.valid("demo", IdentType.InternBruker,
System.currentTimeMillis() / 1000 + sekunderGjenståendeGyldigTid));

AuthenticationFilterDelegate.validerSettKontekst(ri, request);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,6 @@ public String getKonsumentId() {
return konsumentId;
}

// Brukes kun i abakus / dignostikk. Sjekk om kan endres til forProsesstaskUtenSystembruker
@Deprecated(forRemoval = true) // Erstatt med forProsesstaskUtenSystembruker
public static BasisKontekst forProsesstask() {
return new BasisKontekst(SikkerhetContext.SYSTEM, Systembruker.username(), IdentType.Prosess, Systembruker.username());
}

// Denne brukes i prosesstask
public static BasisKontekst forProsesstaskUtenSystembruker() {
var username = "srv" + Optional.ofNullable(Environment.current().application()).orElse("local");
Expand All @@ -64,15 +58,14 @@ public static BasisKontekst forProsesstaskUtenSystembruker() {
}

public static BasisKontekst ikkeAutentisertRequest(String consumerId) {
return new BasisKontekst(SikkerhetContext.REQUEST, null, null, ensureCunsumerId(consumerId));
var consumer = Optional.ofNullable(consumerId)
.or(() -> Optional.ofNullable(Environment.current().application()).map(a -> "srv" + a))
.orElse("srvlocal");
return new BasisKontekst(SikkerhetContext.REQUEST, null, null, consumer);
}

static BasisKontekst tomKontekst() {
return new BasisKontekst(null, null, null, null);
}

protected static String ensureCunsumerId(String consumerId) {
return consumerId != null ? consumerId : Systembruker.username();
}

}
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
package no.nav.vedtak.sikkerhet.kontekst;

import java.util.Objects;
import java.util.regex.Pattern;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public enum IdentType {
// Case definert av NAV "standard". Brukes i ABAC policies. Til bruk i tokenprovider/obo-logikk
Systemressurs, // Innkommende kall fra andre systembrukere
Expand All @@ -16,28 +10,8 @@ public enum IdentType {
Prosess // Ingen kjent bruk - foreslås brukt for prosesstasks
;

private static final Logger LOG = LoggerFactory.getLogger(IdentType.class);

private static final Pattern VALID_AKTØRID = Pattern.compile("^\\d{13}$", Pattern.CASE_INSENSITIVE);
private static final Pattern VALID_PERSONIDENT = Pattern.compile("^\\d{11}$", Pattern.CASE_INSENSITIVE);
private static final Pattern VALID_ANSATTIDENT = Pattern.compile("^\\w\\d{6}$", Pattern.CASE_INSENSITIVE);

public boolean erSystem() {
return Systemressurs.equals(this) || Prosess.equals(this);
}

public static IdentType utledIdentType(String uid) {
if (Objects.equals(Systembruker.username(), uid)) {
return IdentType.Systemressurs;
} else if (uid != null && (VALID_AKTØRID.matcher(uid).matches() || VALID_PERSONIDENT.matcher(uid).matches())) {
return IdentType.EksternBruker;
} else if (uid != null && uid.startsWith("srv")) {
return IdentType.Systemressurs;
} else if (uid != null && VALID_ANSATTIDENT.matcher(uid).matches()) {
return IdentType.InternBruker;
}
LOG.info("FPFELLES KONTEKST kunne ikke utlede identtype fra {}", uid);
// TODO - her skal det strengt tatt være en exception .... Skal på sikt brukes til oppførsel for tokenprovider
return IdentType.InternBruker;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ void testGetDefaultKontekst() {

@Test
void testSetAndGetSystemKontekst() {
var eksisterende = BasisKontekst.forProsesstask();
var eksisterende = BasisKontekst.forProsesstaskUtenSystembruker();
KontekstHolder.setKontekst(eksisterende);

assertThat(KontekstHolder.harKontekst()).isTrue();
var roundtrip = KontekstHolder.getKontekst();
assertThat(roundtrip).isNotNull();
assertThat(roundtrip.getContext()).isEqualTo(SikkerhetContext.SYSTEM);
assertThat(roundtrip.getUid()).isEqualTo(Systembruker.username());
assertThat(roundtrip.getKompaktUid()).isEqualTo(Systembruker.username());
assertThat(roundtrip.getUid()).isEqualTo("srvvtp");
assertThat(roundtrip.getKompaktUid()).isEqualTo("srvvtp");
assertThat(roundtrip.getIdentType()).isEqualTo(IdentType.Prosess);

KontekstHolder.fjernKontekst();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package no.nav.vedtak.sikkerhet.oidc.config;

public enum OpenIDProvider {
STS,
AZUREAD,
TOKENX
}
Loading

0 comments on commit 5a0bb6e

Please sign in to comment.