Skip to content

Commit

Permalink
Sanere utgående STS, standardisere proxy, maskinporten (#1378)
Browse files Browse the repository at this point in the history
* Sanere utgående STS, standardisere proxy, maskinporten

* Justere levetid assertions og cache-evict
  • Loading branch information
jolarsen authored Aug 21, 2024
1 parent fcbecc7 commit 2afe408
Show file tree
Hide file tree
Showing 21 changed files with 393 additions and 274 deletions.
Original file line number Diff line number Diff line change
@@ -1,30 +1,15 @@
package no.nav.vedtak.klient.http;

import no.nav.foreldrepenger.konfig.Environment;

import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.time.Duration;
import java.util.Optional;

public final class ProxyHttpClient extends BaseHttpClient {
private static final Environment ENV = Environment.current();

private static final String AZURE_HTTP_PROXY = "azure.http.proxy";
private static final String PROXY_KEY = "proxy.url";
private static final String DEFAULT_PROXY_URL = "http://webproxy.nais:8088";

private static ProxyHttpClient CLIENT;

private ProxyHttpClient() {
super(HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(15))
.proxy(Optional.ofNullable(ENV.isFss() ? URI.create(ENV.getProperty(AZURE_HTTP_PROXY, getDefaultProxy())) : null)
.map(p -> new InetSocketAddress(p.getHost(), p.getPort()))
.map(ProxySelector::of)
.orElse(HttpClient.Builder.NO_PROXY)).build());
.proxy(ProxyProperty.getProxySelectorIfFSS()).build());
}

public static synchronized ProxyHttpClient client() {
Expand All @@ -36,7 +21,4 @@ public static synchronized ProxyHttpClient client() {
return inst;
}

private static String getDefaultProxy() {
return ENV.getProperty(PROXY_KEY, DEFAULT_PROXY_URL);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
package no.nav.vedtak.klient.http;

import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.util.Optional;

import no.nav.foreldrepenger.konfig.Environment;

/**
* Standard navn på environment injisert av NAIS når maskinporten er enabled
* Dvs naiserator:spec:maskinporten:enabled: true
*/
public class ProxyProperty {
private static final Environment ENV = Environment.current();

private static final String AZURE_HTTP_PROXY = "azure.http.proxy";
private static final String DEFAULT_PROXY_URL = "http://webproxy.nais:8088";

private ProxyProperty() {
}

public static URI getProxy() {
return URI.create(ENV.getProperty(AZURE_HTTP_PROXY, DEFAULT_PROXY_URL));
}

public static URI getProxyIfFSS() {
return ENV.isFss() ? getProxy() : null;
}

public static ProxySelector getProxySelector() {
var proxy = getProxy();
return ProxySelector.of(new InetSocketAddress(proxy.getHost(), proxy.getPort()));
}

public static ProxySelector getProxySelectorIfFSS() {
return ENV.isFss() ? getProxySelector() : HttpClient.Builder.NO_PROXY;
}

public static ProxySelector getProxySelector(URI proxy) {
return Optional.ofNullable(proxy)
.map(p -> new InetSocketAddress(p.getHost(), p.getPort()))
.map(ProxySelector::of)
.orElse(HttpClient.Builder.NO_PROXY);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package no.nav.vedtak.sikkerhet.oidc.config;

/**
* Standard navn på environment injisert av NAIS når maskinporten er enabled
* Dvs naiserator:spec:maskinporten:enabled: true
*/
public enum MaskinportenProperty {
MASKINPORTEN_CLIENT_ID,
MASKINPORTEN_CLIENT_JWK,
MASKINPORTEN_SCOPES, // Må angis i naiserator:spec:maskinporten:scopes:consumes: (-name: "<scope>")
MASKINPORTEN_WELL_KNOWN_URL, // Sanere bruk av well known - bruk heller NAIS/env
MASKINPORTEN_ISSUER,
MASKINPORTEN_TOKEN_ENDPOINT

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import no.nav.foreldrepenger.konfig.Environment;
import no.nav.vedtak.exception.TekniskException;
import no.nav.vedtak.klient.http.ProxyProperty;
import no.nav.vedtak.sikkerhet.kontekst.Systembruker;
import no.nav.vedtak.sikkerhet.oidc.config.AzureProperty;
import no.nav.vedtak.sikkerhet.oidc.config.OpenIDConfiguration;
Expand All @@ -29,10 +30,6 @@ public final class OidcProviderConfig {
private static final Logger LOG = LoggerFactory.getLogger(OidcProviderConfig.class);

private static final String STS_WELL_KNOWN_URL = "oidc.sts.well.known.url";
private static final String AZURE_HTTP_PROXY = "azure.http.proxy"; // settes ikke av naiserator
private static final String PROXY_KEY = "proxy.url"; // FP-oppsett lite brukt
private static final String DEFAULT_PROXY_URL = "http://webproxy.nais:8088";

private static Set<OpenIDConfiguration> providers = new HashSet<>();

private final Set<OpenIDConfiguration> instanceProviders;
Expand Down Expand Up @@ -116,7 +113,7 @@ private static OpenIDConfiguration createStsConfiguration(String wellKnownUrl) {

@SuppressWarnings("unused")
private static OpenIDConfiguration createAzureAppConfiguration() {
var proxyUrl = (ENV.isFss() && ENV.isProd()) ? URI.create(ENV.getProperty(AZURE_HTTP_PROXY, getDefaultProxy())) : null;
var proxyUrl = (ENV.isFss() && ENV.isProd()) ? ProxyProperty.getProxy() : null;
return createConfiguration(OpenIDProvider.AZUREAD,
getAzureProperty(AzureProperty.AZURE_OPENID_CONFIG_ISSUER),
getAzureProperty(AzureProperty.AZURE_OPENID_CONFIG_JWKS_URI),
Expand Down Expand Up @@ -172,10 +169,6 @@ private static OpenIDConfiguration createConfiguration(OpenIDProvider type,
skipAudienceValidation);
}

private static String getDefaultProxy() {
return ENV.getProperty(PROXY_KEY, DEFAULT_PROXY_URL);
}

private static URI tilURI(String url, String key, OpenIDProvider provider) {
try {
return URI.create(url);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package no.nav.vedtak.sikkerhet.oidc.config.impl;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
Expand All @@ -19,6 +17,7 @@
import com.fasterxml.jackson.databind.ObjectReader;

import no.nav.vedtak.exception.TekniskException;
import no.nav.vedtak.klient.http.ProxyProperty;
import no.nav.vedtak.mapper.json.DefaultJsonMapper;

public class WellKnownConfigurationHelper {
Expand All @@ -28,7 +27,7 @@ public class WellKnownConfigurationHelper {

public static final String STANDARD_WELL_KNOWN_PATH = ".well-known/openid-configuration";

private static Map<String, WellKnownOpenIdConfiguration> wellKnownConfigMap = Collections.synchronizedMap(new LinkedHashMap<>());
private static final Map<String, WellKnownOpenIdConfiguration> wellKnownConfigMap = Collections.synchronizedMap(new LinkedHashMap<>());

public static WellKnownOpenIdConfiguration getWellKnownConfig(URI wellKnownUrl) {
return getWellKnownConfig(wellKnownUrl.toString(), null);
Expand Down Expand Up @@ -66,19 +65,17 @@ static Optional<String> getTokenEndpointFra(String wellKnownURL, URI proxyUrl) {
}

private static WellKnownOpenIdConfiguration hentWellKnownConfig(String wellKnownURL, URI proxy) {
try {
if (wellKnownURL == null) {
return null;
}
if (!wellKnownURL.toLowerCase().contains(STANDARD_WELL_KNOWN_PATH)) {
// TODO: øk til warn eller prøv å legge på / standard path med
LOG.info("WELLKNOWN OPENID-CONFIGURATION url uten standard suffix {}", wellKnownURL);
}
var useProxySelector = Optional.ofNullable(proxy)
.map(p -> new InetSocketAddress(p.getHost(), p.getPort()))
.map(ProxySelector::of)
.orElse(HttpClient.Builder.NO_PROXY);
var client = HttpClient.newBuilder().connectTimeout(Duration.ofSeconds(10)).proxy(useProxySelector).build();
if (wellKnownURL == null) {
return null;
}
if (!wellKnownURL.toLowerCase().contains(STANDARD_WELL_KNOWN_PATH)) {
// TODO: øk til warn eller prøv å legge på / standard path med
LOG.info("WELLKNOWN OPENID-CONFIGURATION url uten standard suffix {}", wellKnownURL);
}
try (var client = HttpClient.newBuilder()
.connectTimeout(Duration.ofSeconds(10))
.proxy(ProxyProperty.getProxySelector(proxy))
.build()) {
var request = HttpRequest.newBuilder().uri(URI.create(wellKnownURL)).header("accept", "application/json").GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString()).body();
return response != null ? READER.readValue(response) : null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,6 @@
import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
Expand All @@ -22,6 +20,7 @@
import org.slf4j.LoggerFactory;

import no.nav.vedtak.exception.TekniskException;
import no.nav.vedtak.klient.http.ProxyProperty;

public class JwksKeyHandlerImpl implements JwksKeyHandler {

Expand Down Expand Up @@ -88,19 +87,14 @@ private static String nativeGet(URI url, boolean useProxyForJwks, URI proxy) {
if (url == null) {
throw new TekniskException("F-836283", "Mangler konfigurasjon av jwks url");
}
try {
if (useProxyForJwks && proxy == null) {
throw kunneIkkeOppdatereJwksCache(url, new IllegalArgumentException("Skal bruke proxy, men ingen verdi angitt"));
}
var useProxySelector = Optional.ofNullable(proxy)
.map(p -> new InetSocketAddress(p.getHost(), p.getPort()))
.map(ProxySelector::of)
.orElse(HttpClient.Builder.NO_PROXY);
var client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NEVER)
.connectTimeout(Duration.ofSeconds(20))
.proxy(useProxySelector)
.build();
if (useProxyForJwks && proxy == null) {
throw kunneIkkeOppdatereJwksCache(url, new IllegalArgumentException("Skal bruke proxy, men ingen verdi angitt"));
}
try (var client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NEVER)
.connectTimeout(Duration.ofSeconds(20))
.proxy(ProxyProperty.getProxySelector(proxy))
.build()) {

var request = HttpRequest.newBuilder().header("Accept", "application/json").timeout(Duration.ofSeconds(10)).uri(url).GET().build();
var response = client.send(request, HttpResponse.BodyHandlers.ofString(UTF_8));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,7 @@
import no.nav.vedtak.sikkerhet.oidc.config.OpenIDProvider;
import no.nav.vedtak.sikkerhet.oidc.token.impl.AzureBrukerTokenKlient;
import no.nav.vedtak.sikkerhet.oidc.token.impl.AzureSystemTokenKlient;
import no.nav.vedtak.sikkerhet.oidc.token.impl.StsSystemTokenKlient;
import no.nav.vedtak.sikkerhet.oidc.token.impl.TokenXExchangeKlient;
import no.nav.vedtak.sikkerhet.tokenx.TokenXchange;

public final class TokenProvider {

Expand Down Expand Up @@ -52,30 +50,13 @@ private static OpenIDToken getOutgoingTokenFor(RequestKontekst requestKontekst,
var identType = Optional.ofNullable(requestKontekst.getIdentType()).orElse(IdentType.InternBruker);
return switch (providerIncoming) {
case AZUREAD -> identType.erSystem() ? getAzureSystemToken(scopes) : veksleAzureAccessToken(requestKontekst.getUid(), incoming, scopes);
case TOKENX -> TokenXchange.exchange(incoming, scopes);
case TOKENX -> tokenXchange(incoming, scopes);
case STS -> getAzureSystemToken(scopes);
};
}

public static OpenIDToken getTokenForSystem() {
return getTokenForSystem(OpenIDProvider.STS, null);
}

public static OpenIDToken getTokenXFraKontekst() {
var kontekst = KONTEKST_PROVIDER.getKontekst();
if (kontekst instanceof RequestKontekst requestKontekst) {
return OpenIDProvider.TOKENX.equals(getProvider(requestKontekst.getToken())) ? requestKontekst.getToken() : null;
} else {
throw new IllegalStateException("Mangler SikkerhetContext - skal ikke provide token");
}
}

public static OpenIDToken getTokenForSystem(OpenIDProvider provider, String scopes) {
return switch (provider) {
case AZUREAD -> getAzureSystemToken(scopes);
case STS -> getStsSystemToken();
case TOKENX -> throw new IllegalStateException("Ikke bruk TokenX til kall i systemkontekst");
};
public static OpenIDToken getTokenForSystem(String scopes) {
return getAzureSystemToken(scopes);
}

// Endre til AzureClientId ved overgang til system = azure
Expand All @@ -91,10 +72,6 @@ public static String getCurrentConsumerId() {
return Optional.ofNullable(kontekst.getKonsumentId()).orElseGet(kontekst::getUid);
}

private static OpenIDToken getStsSystemToken() {
return StsSystemTokenKlient.hentAccessToken();
}

private static OpenIDToken getAzureSystemToken(String scopes) {
return AzureSystemTokenKlient.instance().hentAccessToken(scopes);
}
Expand All @@ -103,9 +80,8 @@ private static OpenIDToken veksleAzureAccessToken(String uid, OpenIDToken incomi
return AzureBrukerTokenKlient.instance().oboExchangeToken(uid, incoming, scopes);
}

public static OpenIDToken exchangeTokenX(OpenIDToken token, String assertion, String scopes) {
// Assertion må være generert av den som skal bytte. Et JWT, RSA-signert, basert på injisert private jwk
return TokenXExchangeKlient.instance().exchangeToken(token, assertion, scopes);
public static OpenIDToken tokenXchange(OpenIDToken token, String scopes) {
return TokenXExchangeKlient.instance().exchangeToken(token, scopes);
}

private static OpenIDProvider getProvider(OpenIDToken token) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,37 +3,43 @@
import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.Optional;

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

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectReader;

import no.nav.vedtak.exception.TekniskException;
import no.nav.vedtak.klient.http.ProxyProperty;
import no.nav.vedtak.mapper.json.DefaultJsonMapper;

public class GeneriskTokenKlient {

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

private static final ObjectReader READER = DefaultJsonMapper.getObjectMapper().readerFor(OidcTokenResponse.class);

public static OidcTokenResponse hentTokenRetryable(HttpRequest request, URI proxy, int retries) {
int i = retries;
while (i-- > 0) {
try {
return hentToken(request, proxy);
} catch (TekniskException e) {
LOG.info("Feilet {}. gang ved henting av token. Prøver på nytt", retries - i, e);
}
}
return hentToken(request, proxy);
}


public static OidcTokenResponse hentToken(HttpRequest request, URI proxy) {
try {
var useProxySelector = Optional.ofNullable(proxy)
.map(p -> new InetSocketAddress(p.getHost(), p.getPort()))
.map(ProxySelector::of)
.orElse(HttpClient.Builder.NO_PROXY);
var client = HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NEVER)
.connectTimeout(Duration.ofSeconds(20))
.proxy(useProxySelector)
.build();
try (var client = hentEllerByggHttpClient(proxy)) { // På sikt vurder å bruke en generell klient eller å cache. De er blitt autocloseable
var response = client.send(request, HttpResponse.BodyHandlers.ofString(UTF_8));
if (response == null || response.body() == null) {
throw new TekniskException("F-157385", "Kunne ikke hente token");
Expand All @@ -48,4 +54,13 @@ public static OidcTokenResponse hentToken(HttpRequest request, URI proxy) {
throw new TekniskException("F-432938", "InterruptedException ved henting av token", e);
}
}

private static HttpClient hentEllerByggHttpClient(URI proxy) {
return HttpClient.newBuilder()
.followRedirects(HttpClient.Redirect.NEVER)
.connectTimeout(Duration.ofSeconds(15))
.proxy(ProxyProperty.getProxySelector(proxy))
.build();
}

}
Loading

0 comments on commit 2afe408

Please sign in to comment.