Skip to content

Commit

Permalink
TFP-5952 AntiABAC fase 1, regler og struktur
Browse files Browse the repository at this point in the history
  • Loading branch information
jolarsen committed Jan 19, 2025
1 parent cc4be4f commit ff259f9
Show file tree
Hide file tree
Showing 28 changed files with 1,381 additions and 115 deletions.
8 changes: 2 additions & 6 deletions felles/abac-kontekst/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,17 +14,13 @@

<dependencies>
<dependency>
<groupId>jakarta.enterprise</groupId>
<artifactId>jakarta.enterprise.cdi-api</artifactId>
<groupId>no.nav.foreldrepenger.felles.integrasjon</groupId>
<artifactId>felles-integrasjon-rest-klient</artifactId>
</dependency>
<dependency>
<groupId>no.nav.foreldrepenger.felles</groupId>
<artifactId>felles-kontekst</artifactId>
</dependency>
<dependency>
<groupId>no.nav.foreldrepenger.felles</groupId>
<artifactId>felles-oidc</artifactId>
</dependency>
<dependency>
<groupId>no.nav.foreldrepenger.felles</groupId>
<artifactId>felles-abac</artifactId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package no.nav.foreldrepenger.sikkerhet.abac;

import java.util.Set;
import java.util.UUID;

import jakarta.enterprise.context.Dependent;

import no.nav.vedtak.sikkerhet.abac.TokenProvider;
import no.nav.vedtak.sikkerhet.kontekst.AnsattGruppe;
import no.nav.vedtak.sikkerhet.kontekst.DefaultRequestKontekstProvider;
import no.nav.vedtak.sikkerhet.kontekst.IdentType;
import no.nav.vedtak.sikkerhet.kontekst.RequestKontekst;
import no.nav.vedtak.sikkerhet.kontekst.RequestKontekstProvider;
import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken;

Expand All @@ -27,4 +31,14 @@ public IdentType getIdentType() {
public OpenIDToken openIdToken() {
return PROVIDER.getToken();
}

@Override
public UUID getOid() {
return PROVIDER.getOid();
}

@Override
public Set<AnsattGruppe> getAnsattGrupper() {
return PROVIDER.getAnsattGrupper();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package no.nav.foreldrepenger.sikkerhet.populasjon;

import java.net.URI;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.ws.rs.core.UriBuilder;

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

import no.nav.vedtak.felles.integrasjon.rest.FpApplication;
import no.nav.vedtak.felles.integrasjon.rest.RestClient;
import no.nav.vedtak.felles.integrasjon.rest.RestClientConfig;
import no.nav.vedtak.felles.integrasjon.rest.RestConfig;
import no.nav.vedtak.felles.integrasjon.rest.RestRequest;
import no.nav.vedtak.felles.integrasjon.rest.TokenFlow;
import no.nav.vedtak.sikkerhet.abac.policy.Tilgangsvurdering;
import no.nav.vedtak.sikkerhet.populasjon.PopulasjonEksternRequest;
import no.nav.vedtak.sikkerhet.populasjon.PopulasjonInternRequest;
import no.nav.vedtak.sikkerhet.populasjon.PopulasjonKlient;

@ApplicationScoped
@RestClientConfig(tokenConfig = TokenFlow.AZUREAD_CC, application = FpApplication.FPTILGANG)
public class TilgangKlient implements PopulasjonKlient {

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

private final URI internBrukerUri;

private final URI eksternBrukerUri;
private final RestClient klient;
private final RestConfig restConfig;

public TilgangKlient() {
this.klient = RestClient.client();
this.restConfig = RestConfig.forClient(this.getClass());
this.internBrukerUri = UriBuilder.fromUri(restConfig.fpContextPath())
.path("/api/populasjon/internbruker")
.build();
this.eksternBrukerUri = UriBuilder.fromUri(restConfig.fpContextPath())
.path("/api/populasjon/eksternbruker")
.build();
}

@Override
public Tilgangsvurdering vurderTilgang(PopulasjonInternRequest request) {
var rrequest = RestRequest.newPOSTJson(request, internBrukerUri, restConfig);
//return klient.send(rrequest, Tilgangsvurdering.class);
return Tilgangsvurdering.godkjenn();
}

@Override
public Tilgangsvurdering vurderTilgang(PopulasjonEksternRequest request) {
var rrequest = RestRequest.newPOSTJson(request, eksternBrukerUri, restConfig);
//return klient.send(rrequest, Tilgangsvurdering.class);
return Tilgangsvurdering.godkjenn();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ private Object ikkeTilgang(Tilgangsbeslutning beslutning) {
if (!erSystembrukerKall(beslutning.beskyttetRessursAttributter())) {
abacAuditlogger.loggDeny(tokenProvider.getUid(), beslutning);
} else {
LOG.info("ABAC AVSLAG SYSTEMBRUKER {}", beslutning.beskyttetRessursAttributter().getUserId());
LOG.info("ABAC AVSLAG SYSTEMBRUKER {}", beslutning.beskyttetRessursAttributter().getBrukerId());
}

switch (beslutning.beslutningKode()) {
Expand All @@ -83,8 +83,7 @@ private Object ikkeTilgang(Tilgangsbeslutning beslutning) {

private boolean erSystembrukerKall(BeskyttetRessursAttributter beskyttetRessursAttributter) {
return Optional.ofNullable(beskyttetRessursAttributter)
.map(BeskyttetRessursAttributter::getToken)
.map(Token::getIdentType)
.map(BeskyttetRessursAttributter::getIdentType)
.filter(IdentType::erSystem)
.isPresent();
}
Expand All @@ -94,10 +93,13 @@ private BeskyttetRessursAttributter hentBeskyttetRessursAttributter(InvocationCo
var method = invocationContext.getMethod();
var beskyttetRessurs = method.getAnnotation(BeskyttetRessurs.class);

var token = Token.withOidcToken(tokenProvider.openIdToken(), tokenProvider.getUid(), tokenProvider.getIdentType());
var token = Token.withOidcToken(tokenProvider.openIdToken());

return BeskyttetRessursAttributter.builder()
.medUserId(tokenProvider.getUid())
.medBrukerId(tokenProvider.getUid())
.medBrukerOid(tokenProvider.getOid())
.medIdentType(tokenProvider.getIdentType())
.medAnsattGrupper(tokenProvider.getAnsattGrupper())
.medToken(token)
.medActionType(beskyttetRessurs.actionType())
.medAvailabilityType(beskyttetRessurs.availabilityType())
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,39 @@
package no.nav.vedtak.sikkerhet.abac;

import no.nav.vedtak.sikkerhet.abac.internal.BeskyttetRessursAttributter;
import no.nav.vedtak.sikkerhet.abac.pdp.AppRessursData;
import no.nav.vedtak.sikkerhet.abac.policy.Tilgangsvurdering;

/**
* Dette grensesnittet må implementeres av alle applikasjoner:
* - Alle må implementere lagAppRessursData
* - De applikasjonene (tilbake, inntektsmelding) som skal kalle K9 sin PDP/abac må implementere abacDomene
* -
*/
public interface PdpRequestBuilder {

default String abacDomene() {
return "foreldrepenger";
}

AppRessursData lagAppRessursData(AbacDataAttributter dataAttributter);

// Trenger egentlig bare sette BEHANDLING_STATUS + FAGSAK_STATUS i tilfelle FAGSAK / UPDATE for skrivetilgangs-sjekk
default AppRessursData lagAppRessursDataForSystembruker(AbacDataAttributter dataAttributter) {
return lagAppRessursData(dataAttributter);
}


default boolean skalVurdereTilgangLokalt(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData) {
return false;
}

// Fortsette med vanlig tilgangskontroll eller bruke svar fra lokal vurdering
default boolean kunLokalVurdering(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData) {
return false;
}

default Tilgangsvurdering vurderTilgangLokalt(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData) {
throw new IllegalArgumentException("Utviklerfeil: viser lokal tilgangsvurdering, men ikke implementert metode");
}
}
146 changes: 99 additions & 47 deletions felles/abac/src/main/java/no/nav/vedtak/sikkerhet/abac/PepImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,99 +3,151 @@
import static no.nav.vedtak.sikkerhet.abac.AbacResultat.AVSLÅTT_ANNEN_ÅRSAK;
import static no.nav.vedtak.sikkerhet.abac.AbacResultat.GODKJENT;

import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Objects;

import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Default;
import jakarta.inject.Inject;

import no.nav.foreldrepenger.konfig.Cluster;
import no.nav.foreldrepenger.konfig.Environment;
import no.nav.vedtak.sikkerhet.abac.beskyttet.AvailabilityType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import no.nav.vedtak.sikkerhet.abac.beskyttet.ActionType;
import no.nav.vedtak.sikkerhet.abac.internal.BeskyttetRessursAttributter;
import no.nav.vedtak.sikkerhet.abac.pdp.AppRessursData;
import no.nav.vedtak.sikkerhet.abac.policy.EksternBrukerPolicies;
import no.nav.vedtak.sikkerhet.abac.policy.ForeldrepengerAttributter;
import no.nav.vedtak.sikkerhet.abac.policy.InternBrukerPolicies;
import no.nav.vedtak.sikkerhet.abac.policy.SystemressursPolicies;
import no.nav.vedtak.sikkerhet.abac.policy.Tilgangsvurdering;
import no.nav.vedtak.sikkerhet.kontekst.AnsattGruppe;
import no.nav.vedtak.sikkerhet.kontekst.IdentType;
import no.nav.vedtak.sikkerhet.oidc.config.AzureProperty;
import no.nav.vedtak.sikkerhet.oidc.config.OpenIDProvider;

import no.nav.vedtak.sikkerhet.populasjon.PopulasjonEksternRequest;
import no.nav.vedtak.sikkerhet.populasjon.PopulasjonInternRequest;
import no.nav.vedtak.sikkerhet.populasjon.PopulasjonKlient;

/**
* Dette er strengt tatt PDP (eller en PDP-proxy før kall til Abac).
* Interceptor er strengt tatt PEP (policy enforcement point)
*/
@Default
@ApplicationScoped
public class PepImpl implements Pep {

private static final Logger LOG = LoggerFactory.getLogger(PepImpl.class);
private static final String PIP = ForeldrepengerAttributter.RESOURCE_TYPE_INTERNAL_PIP;
private static final Environment ENV = Environment.current();

private PdpKlient pdpKlient;
private PdpRequestBuilder builder;
private PopulasjonKlient populasjonKlient;
private PdpRequestBuilder pdpRequestBuilder;

private String preAuthorized;
private Cluster residentCluster;
private String residentNamespace;

PepImpl() {
// CDI proxy
}

@Inject
public PepImpl(PdpKlient pdpKlient, PdpRequestBuilder pdpRequestBuilder) {
public PepImpl(PdpKlient pdpKlient, PopulasjonKlient populasjonKlient, PdpRequestBuilder pdpRequestBuilder) {
this.pdpKlient = pdpKlient;
this.builder = pdpRequestBuilder;
this.preAuthorized = ENV.getProperty(AzureProperty.AZURE_APP_PRE_AUTHORIZED_APPS.name()); // eg json array av objekt("name", "clientId")
this.residentCluster = ENV.getCluster();
this.residentNamespace = ENV.namespace();
this.populasjonKlient = populasjonKlient;
this.pdpRequestBuilder = pdpRequestBuilder;
}

@Override
public Tilgangsbeslutning vurderTilgang(BeskyttetRessursAttributter beskyttetRessursAttributter) {
var appRessurser = builder.lagAppRessursData(beskyttetRessursAttributter.getDataAttributter());
var appRessurser = pdpRequestBuilder.lagAppRessursData(beskyttetRessursAttributter.getDataAttributter());

if (kanForetaLokalTilgangsbeslutning(beskyttetRessursAttributter.getToken())) {
if (IdentType.Systemressurs.equals(beskyttetRessursAttributter.getIdentType())) {
return vurderLokalTilgang(beskyttetRessursAttributter, appRessurser);
} else if (PIP.equals(beskyttetRessursAttributter.getResourceType())) { // pip tilgang bør vurderes kun lokalt
return new Tilgangsbeslutning(AVSLÅTT_ANNEN_ÅRSAK, beskyttetRessursAttributter, appRessurser);
}

return pdpKlient.forespørTilgang(beskyttetRessursAttributter, builder.abacDomene(), appRessurser);
var pdpResultat = pdpKlient.forespørTilgang(beskyttetRessursAttributter, pdpRequestBuilder.abacDomene(), appRessurser);
sammenlignOgLogg(beskyttetRessursAttributter, appRessurser, pdpResultat.beslutningKode());
return pdpResultat;
}

protected Tilgangsbeslutning vurderLokalTilgang(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData) {
var token = beskyttetRessursAttributter.getToken();
var harTilgang = harTilgang(token.getBrukerId(), beskyttetRessursAttributter.getAvailabilityType());
var harTilgang = SystemressursPolicies.riktigClusterNamespacePreAuth(beskyttetRessursAttributter.getBrukerId(), beskyttetRessursAttributter.getAvailabilityType());
return new Tilgangsbeslutning(harTilgang ? GODKJENT : AVSLÅTT_ANNEN_ÅRSAK, beskyttetRessursAttributter, appRessursData);
}

// AzureAD CC kommer med sub som ikke ikke en bruker med vanlige AD-grupper og roller
// 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();
var consumer = token.getBrukerId();

return OpenIDProvider.AZUREAD.equals(token.getOpenIDProvider()) &&
IdentType.Systemressurs.equals(identType) &&
consumer != null &&
preAuthorized != null;
private void sammenlignOgLogg(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData, AbacResultat resultat) {
try {
var lokalt = forespørTilgang(beskyttetRessursAttributter, appRessursData);
if (Objects.equals(lokalt.abacResultat(), resultat)) {
LOG.info("FPEGENTILGANG: samme svar");
} else {
LOG.info("FPEGENTILGANG: ulikt svar - gammel {} ny {}", resultat, lokalt.abacResultat());
}
} catch (Exception e) {
LOG.info("FPEGENTILGANG: feil", e);
}
}

private boolean harTilgang(String consumerId, AvailabilityType availabilityType) {
if (consumerId == null || !preAuthorized.contains(consumerId)) {
return false;
// Skal kunne kalles fra evt subklasser av PepImpl
protected Tilgangsvurdering forespørTilgang(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData) {
if (ActionType.DUMMY.equals(beskyttetRessursAttributter.getActionType())) {
return Tilgangsvurdering.avslåGenerell("ActionType DUMMY ikke støttet");
}
return switch (beskyttetRessursAttributter.getIdentType()) {
case Systemressurs -> SystemressursPolicies.vurderTilgang(beskyttetRessursAttributter, appRessursData);
case InternBruker -> forespørTilgangInternBruker(beskyttetRessursAttributter, appRessursData);
case EksternBruker -> forespørTilgangEksternBruker(beskyttetRessursAttributter, appRessursData);
default -> Tilgangsvurdering.avslåGenerell("Ukjent IdentType");
};
}

if (erISammeKlusterKlasseOgNamespace(consumerId)) {
return true;
private Tilgangsvurdering forespørTilgangInternBruker(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData) {
HashSet<AnsattGruppe> kreverGrupper = new LinkedHashSet<>();
if (pdpRequestBuilder.skalVurdereTilgangLokalt(beskyttetRessursAttributter, appRessursData)) {
var lokalVurdering = pdpRequestBuilder.vurderTilgangLokalt(beskyttetRessursAttributter, appRessursData);
if (!lokalVurdering.fikkTilgang() || pdpRequestBuilder.kunLokalVurdering(beskyttetRessursAttributter, appRessursData)) {
return lokalVurdering;
}
kreverGrupper.addAll(lokalVurdering.kreverGrupper());
}

return AvailabilityType.ALL.equals(availabilityType);
var fagtilgang = InternBrukerPolicies.vurderTilgang(beskyttetRessursAttributter, appRessursData);
if (!fagtilgang.fikkTilgang()) {
return fagtilgang;
}
kreverGrupper.addAll(fagtilgang.kreverGrupper());
if (kreverGrupper.isEmpty() && appRessursData.getFødselsnumre().isEmpty() && appRessursData.getAktørIdSet().isEmpty()) {
// Ikke noe å sjekke for populasjonstilgang
return Tilgangsvurdering.godkjenn();
}
var popRequest = new PopulasjonInternRequest(beskyttetRessursAttributter.getBrukerOid(), kreverGrupper,
appRessursData.getFødselsnumre(), appRessursData.getAktørIdSet());
var popTilgang = populasjonKlient.vurderTilgang(popRequest);
if (popTilgang == null) {
return Tilgangsvurdering.avslåGenerell("Feil ved kontakt med tilgangskontrll");
}
return popTilgang;
}

private boolean erISammeKlusterKlasseOgNamespace(String consumer) {
var elementer = consumer.split(":");
if (elementer.length < 2) {
return false;
private Tilgangsvurdering forespørTilgangEksternBruker(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData) {
if (pdpRequestBuilder.skalVurdereTilgangLokalt(beskyttetRessursAttributter, appRessursData)) {
var lokalVurdering = pdpRequestBuilder.vurderTilgangLokalt(beskyttetRessursAttributter, appRessursData);
if (!lokalVurdering.fikkTilgang() || pdpRequestBuilder.kunLokalVurdering(beskyttetRessursAttributter, appRessursData)) {
return lokalVurdering;
}
}

var consumerCluster = elementer[0];
var consumerNamespace = elementer[1];
return residentCluster.isSameClass(Cluster.of(consumerCluster)) && residentNamespace.equals(consumerNamespace);
var fagtilgang = EksternBrukerPolicies.vurderTilgang(beskyttetRessursAttributter, appRessursData);
if (!fagtilgang.fikkTilgang()) {
return fagtilgang;
}
// Ingen early return - skal sjekke alder på bruker. Kanskje populere attributt ved innsending.
var popRequest = new PopulasjonEksternRequest(beskyttetRessursAttributter.getBrukerId(),
appRessursData.getFødselsnumre(), appRessursData.getAktørIdSet());
var popTilgang = populasjonKlient.vurderTilgang(popRequest);
if (popTilgang == null) {
return Tilgangsvurdering.avslåGenerell("Feil ved kontakt med tilgangskontrll");
}
return popTilgang;
}


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

import no.nav.vedtak.sikkerhet.abac.internal.BeskyttetRessursAttributter;
import no.nav.vedtak.sikkerhet.abac.pdp.AppRessursData;
import no.nav.vedtak.sikkerhet.abac.policy.Tilgangsvurdering;

public interface PopulasjonsTilgang {

Tilgangsvurdering vurderTilgang(BeskyttetRessursAttributter beskyttetRessursAttributter, AppRessursData appRessursData);

}
Loading

0 comments on commit ff259f9

Please sign in to comment.