-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
ABAC-variant med native http og jackson (#1161)
* ABAC-variant med native http og jackson * Non static client and reader
- Loading branch information
Showing
19 changed files
with
972 additions
and
18 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
8 changes: 8 additions & 0 deletions
8
felles/abac/src/main/java/no/nav/vedtak/sikkerhet/pdp2/Pdp2Consumer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
package no.nav.vedtak.sikkerhet.pdp2; | ||
|
||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlRequestBuilder2; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlResponse; | ||
|
||
public interface Pdp2Consumer { | ||
XacmlResponse evaluate(XacmlRequestBuilder2 request); | ||
} |
100 changes: 100 additions & 0 deletions
100
felles/abac/src/main/java/no/nav/vedtak/sikkerhet/pdp2/PdpConsumerImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
package no.nav.vedtak.sikkerhet.pdp2; | ||
|
||
import static java.nio.charset.StandardCharsets.UTF_8; | ||
|
||
import java.io.IOException; | ||
import java.net.URI; | ||
import java.net.http.HttpClient; | ||
import java.net.http.HttpRequest; | ||
import java.time.Duration; | ||
import java.util.Base64; | ||
|
||
import javax.enterprise.context.ApplicationScoped; | ||
import javax.inject.Inject; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import com.fasterxml.jackson.core.JsonProcessingException; | ||
import com.fasterxml.jackson.databind.ObjectReader; | ||
|
||
import no.nav.foreldrepenger.konfig.KonfigVerdi; | ||
import no.nav.vedtak.exception.TekniskException; | ||
import no.nav.vedtak.log.mdc.MDCOperations; | ||
import no.nav.vedtak.mapper.json.DefaultJsonMapper; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlRequestBuilder2; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlResponse; | ||
|
||
@ApplicationScoped | ||
public class PdpConsumerImpl implements Pdp2Consumer { | ||
|
||
private static final String DEFAULT_ABAC_URL = "http://abac-foreldrepenger.teamabac/application/authorize"; | ||
private static final String PDP_ENDPOINT_URL_KEY = "abac.pdp.endpoint.url"; | ||
private static final String SYSTEMBRUKER_USERNAME = "systembruker.username"; | ||
private static final String SYSTEMBRUKER_PASSWORD = "systembruker.password"; // NOSONAR | ||
private static final String MEDIA_TYPE = "application/xacml+json"; | ||
private static final Logger LOG = LoggerFactory.getLogger(PdpConsumerImpl.class); | ||
|
||
private HttpClient client; | ||
private ObjectReader reader; | ||
|
||
private URI pdpUrl; | ||
private String brukernavn; | ||
private String basicCredentials; | ||
|
||
PdpConsumerImpl() { | ||
} // CDI | ||
|
||
/* | ||
* TODO(jol) vurder å hente det som injectes med ENV.getProperty - da kan hele saken gjøres static .... | ||
*/ | ||
@Inject | ||
public PdpConsumerImpl(@KonfigVerdi(value = PDP_ENDPOINT_URL_KEY, defaultVerdi = DEFAULT_ABAC_URL) URI pdpUrl, | ||
@KonfigVerdi(SYSTEMBRUKER_USERNAME) String brukernavn, | ||
@KonfigVerdi(SYSTEMBRUKER_PASSWORD) String passord) { | ||
this.pdpUrl = pdpUrl; | ||
this.brukernavn = brukernavn; | ||
this.basicCredentials = basicCredentials(brukernavn, passord); | ||
// TODO - vurder om bør settes static final? | ||
this.client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).build(); | ||
this.reader = DefaultJsonMapper.getObjectMapper().readerFor(XacmlResponse.class); | ||
} | ||
|
||
@Override | ||
public XacmlResponse evaluate(XacmlRequestBuilder2 xacmlRequest) { | ||
// TODO : hvilke headere trenger abac egentlig - utenom Auth og Content-type | ||
var request = HttpRequest.newBuilder() | ||
.header("Authorization", basicCredentials) | ||
.header("Nav-Consumer-Id", brukernavn) | ||
.header("Nav-Call-Id", MDCOperations.getCallId()) | ||
.header("Nav-Callid", MDCOperations.getCallId()) | ||
.header("Content-type", MEDIA_TYPE) | ||
.timeout(Duration.ofSeconds(5)) | ||
.uri(pdpUrl) | ||
.POST(HttpRequest.BodyPublishers.ofString(DefaultJsonMapper.toJson(xacmlRequest.build()), UTF_8)) | ||
.build(); | ||
|
||
try { | ||
var response = client.send(request, java.net.http.HttpResponse.BodyHandlers.ofString(UTF_8)); | ||
if (response == null || response.statusCode() == 401 || response.body() == null) { | ||
LOG.info("ingen response fra PDP status = {}", response == null ? "null" : response.statusCode()); | ||
throw new TekniskException("F-157385", "Kunne ikke hente svar fra ABAC"); | ||
} | ||
var resultat = reader.readValue(response.body(), XacmlResponse.class); | ||
LOG.trace("PDP2 svar {}", resultat); | ||
return resultat; | ||
} catch (JsonProcessingException e) { | ||
throw new TekniskException("F-208314", "Kunne ikke deserialisere objekt til JSON", e); | ||
} catch (IOException e) { | ||
throw new TekniskException("F-091324", "Uventet IO-exception mot PDP", e); | ||
} catch (InterruptedException e) { | ||
Thread.currentThread().interrupt(); | ||
throw new TekniskException("F-432938", "InterruptedException ved henting av token", e); | ||
} | ||
} | ||
|
||
private static String basicCredentials(String username, String password) { | ||
return "Basic " + Base64.getEncoder().encodeToString(String.format("%s:%s", username, password).getBytes(UTF_8)); | ||
} | ||
|
||
} |
157 changes: 157 additions & 0 deletions
157
felles/abac/src/main/java/no/nav/vedtak/sikkerhet/pdp2/PdpKlientImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,157 @@ | ||
package no.nav.vedtak.sikkerhet.pdp2; | ||
|
||
import static no.nav.foreldrepenger.konfig.Environment.NAIS_APP_NAME; | ||
import static no.nav.vedtak.sikkerhet.abac.NavAbacCommonAttributter.ENVIRONMENT_FELLES_OIDC_TOKEN_BODY; | ||
import static no.nav.vedtak.sikkerhet.abac.NavAbacCommonAttributter.ENVIRONMENT_FELLES_PEP_ID; | ||
import static no.nav.vedtak.sikkerhet.abac.NavAbacCommonAttributter.ENVIRONMENT_FELLES_SAML_TOKEN; | ||
import static no.nav.vedtak.sikkerhet.abac.NavAbacCommonAttributter.ENVIRONMENT_FELLES_TOKENX_TOKEN_BODY; | ||
|
||
import java.nio.charset.StandardCharsets; | ||
import java.text.ParseException; | ||
import java.util.Base64; | ||
import java.util.List; | ||
|
||
import javax.enterprise.context.ApplicationScoped; | ||
import javax.inject.Inject; | ||
import javax.inject.Named; | ||
|
||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
import com.nimbusds.jwt.SignedJWT; | ||
|
||
import no.nav.foreldrepenger.konfig.Environment; | ||
import no.nav.vedtak.exception.TekniskException; | ||
import no.nav.vedtak.log.util.LoggerUtils; | ||
import no.nav.vedtak.sikkerhet.abac.AbacIdToken; | ||
import no.nav.vedtak.sikkerhet.abac.AbacResultat; | ||
import no.nav.vedtak.sikkerhet.abac.Decision; | ||
import no.nav.vedtak.sikkerhet.abac.PdpKlient; | ||
import no.nav.vedtak.sikkerhet.abac.PdpRequest; | ||
import no.nav.vedtak.sikkerhet.abac.Tilgangsbeslutning; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.Advice; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlAttributeSet; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlRequestBuilder2; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlResponse; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlResponseMapper; | ||
|
||
@ApplicationScoped | ||
@Named("pdp2") | ||
public class PdpKlientImpl implements PdpKlient { | ||
|
||
private static final Environment ENV = Environment.current(); | ||
private static final Logger LOG = LoggerFactory.getLogger(PdpKlientImpl.class); | ||
private XacmlRequestBuilder2Tjeneste xamlRequestBuilderTjeneste; | ||
|
||
private Pdp2Consumer pdp; | ||
|
||
public PdpKlientImpl() { | ||
} | ||
|
||
@Inject | ||
public PdpKlientImpl(Pdp2Consumer pdp, XacmlRequestBuilder2Tjeneste xamlRequestBuilderTjeneste) { | ||
this.pdp = pdp; | ||
this.xamlRequestBuilderTjeneste = xamlRequestBuilderTjeneste; | ||
} | ||
|
||
@Override | ||
public Tilgangsbeslutning forespørTilgang(PdpRequest req) { | ||
var builder = xamlRequestBuilderTjeneste.lagXacmlRequestBuilder2(req); | ||
leggPåTokenInformasjon(builder, req); | ||
var response = pdp.evaluate(builder); | ||
var hovedresultat = resultatFraResponse(response); | ||
return new Tilgangsbeslutning(hovedresultat, XacmlResponseMapper.getDecisions(response), req); | ||
} | ||
|
||
static void leggPåTokenInformasjon(XacmlRequestBuilder2 builder, PdpRequest req) { | ||
var attrs = new XacmlAttributeSet(); | ||
attrs.addAttribute(ENVIRONMENT_FELLES_PEP_ID, getPepId()); | ||
var idToken = AbacIdToken.class.cast(req.get(ENVIRONMENT_AUTH_TOKEN)); | ||
switch (idToken.getTokenType()) { | ||
case OIDC: | ||
String key = ENVIRONMENT_FELLES_OIDC_TOKEN_BODY; | ||
LOG.trace("Legger ved token med type oidc på {}", key); | ||
try { | ||
attrs.addAttribute(key, SignedJWT.parse(idToken.getToken()).getPayload().toBase64URL().toString()); | ||
} catch (ParseException e) { | ||
throw new IllegalArgumentException("Ukjent token type"); | ||
} | ||
break; | ||
case TOKENX: | ||
String keyX = ENVIRONMENT_FELLES_TOKENX_TOKEN_BODY; | ||
LOG.trace("Legger IKKE ved token med type tokenX på {}", keyX); | ||
/* | ||
try { | ||
attrs.addAttribute(keyX, | ||
SignedJWT.parse(idToken.getToken()).getPayload().toBase64URL().toString()); | ||
} catch (ParseException e) { | ||
throw new IllegalArgumentException("Ukjent token type"); | ||
} | ||
*/ | ||
break; | ||
case SAML: | ||
LOG.trace("Legger på token med type saml"); | ||
attrs.addAttribute(ENVIRONMENT_FELLES_SAML_TOKEN, base64encode(idToken.getToken())); | ||
break; | ||
} | ||
|
||
builder.addEnvironmentAttributeSet(attrs); | ||
} | ||
|
||
private static String base64encode(String samlToken) { | ||
return Base64.getEncoder().encodeToString(samlToken.getBytes(StandardCharsets.UTF_8)); | ||
} | ||
|
||
private static AbacResultat resultatFraResponse(XacmlResponse response) { | ||
var decisions = XacmlResponseMapper.getDecisions(response); | ||
|
||
for (var decision : decisions) { | ||
if (decision == Decision.Indeterminate) { | ||
throw new TekniskException("F-080281", | ||
String.format("Decision %s fra PDP, dette skal aldri skje. Full JSON response: %s", decision, response)); | ||
} | ||
} | ||
|
||
var biasedDecision = createAggregatedDecision(decisions); | ||
handlObligation(response); | ||
|
||
if (biasedDecision == Decision.Permit) { | ||
return AbacResultat.GODKJENT; | ||
} | ||
|
||
var denyAdvice = XacmlResponseMapper.getAdvice(response); | ||
|
||
if (LOG.isDebugEnabled()) { | ||
LOG.debug("Deny fra PDP, advice var: {}", LoggerUtils.toStringWithoutLineBreaks(denyAdvice)); | ||
} | ||
if (denyAdvice.contains(Advice.DENY_KODE_6)) { | ||
return AbacResultat.AVSLÅTT_KODE_6; | ||
} | ||
if (denyAdvice.contains(Advice.DENY_KODE_7)) { | ||
return AbacResultat.AVSLÅTT_KODE_7; | ||
} | ||
if (denyAdvice.contains(Advice.DENY_EGEN_ANSATT)) { | ||
return AbacResultat.AVSLÅTT_EGEN_ANSATT; | ||
} | ||
return AbacResultat.AVSLÅTT_ANNEN_ÅRSAK; | ||
} | ||
|
||
private static Decision createAggregatedDecision(List<Decision> decisions) { | ||
for (var decision : decisions) { | ||
if (decision != Decision.Permit) | ||
return Decision.Deny; | ||
} | ||
return Decision.Permit; | ||
} | ||
|
||
private static void handlObligation(XacmlResponse response) { | ||
var obligations = XacmlResponseMapper.getObligations(response); | ||
if (!obligations.isEmpty()) { | ||
throw new TekniskException("F-576027", String.format("Mottok ukjente obligations fra PDP: %s", obligations)); | ||
} | ||
} | ||
|
||
private static String getPepId() { | ||
return ENV.getProperty(NAIS_APP_NAME, "local-app"); | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
felles/abac/src/main/java/no/nav/vedtak/sikkerhet/pdp2/XacmlRequestBuilder2Tjeneste.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package no.nav.vedtak.sikkerhet.pdp2; | ||
|
||
import no.nav.vedtak.sikkerhet.abac.PdpRequest; | ||
import no.nav.vedtak.sikkerhet.pdp2.xacml.XacmlRequestBuilder2; | ||
|
||
public interface XacmlRequestBuilder2Tjeneste { | ||
/** | ||
* Legger på de attributter som trengs for vurdering av abac-policy | ||
* | ||
* @param pdpRequest attributter som systemet har plukket ut som relevant for | ||
* requestet | ||
* @return XacmlRequestBuilder | ||
*/ | ||
XacmlRequestBuilder2 lagXacmlRequestBuilder2(PdpRequest req); | ||
} |
Oops, something went wrong.