Skip to content

Commit

Permalink
Refaktorering OIDC Provider konfig og Token Validator konfig. (#1004)
Browse files Browse the repository at this point in the history
  • Loading branch information
mrsladek authored Nov 24, 2021
1 parent 3fa5d52 commit abcea15
Show file tree
Hide file tree
Showing 11 changed files with 220 additions and 164 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package no.nav.vedtak.isso;

import static no.nav.vedtak.sikkerhet.oidc.OidcProviderConfig.OPEN_AM_WELL_KNOWN_URL;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
Expand Down Expand Up @@ -36,7 +38,7 @@
import no.nav.vedtak.isso.config.ServerInfo;
import no.nav.vedtak.sikkerhet.domene.IdTokenAndRefreshToken;
import no.nav.vedtak.sikkerhet.oidc.IdTokenAndRefreshTokenProvider;
import no.nav.vedtak.sikkerhet.oidc.OpenIDProviderConfigProvider;
import no.nav.vedtak.sikkerhet.oidc.OidcProviderConfig;
import no.nav.vedtak.sikkerhet.oidc.WellKnownConfigurationHelper;

// TODO, denne klassen er en katastrofe
Expand Down Expand Up @@ -70,21 +72,25 @@ public OpenAMHelper() {
}

public static String getIssoHostUrl() {
return Optional.ofNullable(OpenIDProviderConfigProvider.OPEN_AM_WELL_KNOWN_URL)
return Optional.ofNullable(ENV.getProperty(OPEN_AM_WELL_KNOWN_URL))
.map(url -> url.replace(WELL_KNOWN_ENDPOINT, ""))
.orElse(ENV.getProperty(OPEN_ID_CONNECT_ISSO_HOST));
}

public static String getIssoUserName() {
return Optional.ofNullable(ENV.getProperty(OpenIDProviderConfigProvider.OPEN_AM_CLIENT_ID)).orElse(ENV.getProperty(OPEN_ID_CONNECT_USERNAME));
return Optional.ofNullable(ENV.getProperty(OidcProviderConfig.OPEN_AM_CLIENT_ID))
.orElse(ENV.getProperty(OPEN_ID_CONNECT_USERNAME));
}

public static String getIssoPassword() {
return Optional.ofNullable(ENV.getProperty(OpenIDProviderConfigProvider.OPEN_AM_CLIENT_SECRET)).orElse(ENV.getProperty(OPEN_ID_CONNECT_PASSWORD));
return Optional.ofNullable(ENV.getProperty(OidcProviderConfig.OPEN_AM_CLIENT_SECRET))
.orElse(ENV.getProperty(OPEN_ID_CONNECT_PASSWORD));
}

public static AuthorizationServerMetadata getOpenAmWellKnownConfig() {
return WellKnownConfigurationHelper.getWellKnownConfig(Optional.ofNullable(OpenIDProviderConfigProvider.OPEN_AM_WELL_KNOWN_URL).orElse(ENV.getProperty(OPEN_ID_CONNECT_ISSO_HOST) + WELL_KNOWN_ENDPOINT));
return WellKnownConfigurationHelper.getWellKnownConfig
(Optional.ofNullable(ENV.getProperty(OPEN_AM_WELL_KNOWN_URL))
.orElse(ENV.getProperty(OPEN_ID_CONNECT_ISSO_HOST) + WELL_KNOWN_ENDPOINT));
}

public static String getIssoIssuerUrl() {
Expand Down Expand Up @@ -116,8 +122,6 @@ IdTokenAndRefreshToken getToken(String brukernavn, String passord) throws IOExce
}
}



private void authenticateUser(CloseableHttpClient httpClient, CookieStore cookieStore, String brukernavn,
String passord) throws IOException {
String jsonAuthUrl = getIssoHostUrl().replace(OAUTH2_ENDPOINT, JSON_AUTH_ENDPOINT);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import static javax.ws.rs.core.Response.Status.FORBIDDEN;
import static no.nav.vedtak.sikkerhet.Constants.ID_TOKEN_COOKIE_NAME;
import static no.nav.vedtak.sikkerhet.Constants.REFRESH_TOKEN_COOKIE_NAME;
import static no.nav.vedtak.sikkerhet.oidc.JwtUtil.getIssuser;
import static no.nav.vedtak.sikkerhet.oidc.JwtUtil.getIssuer;

import java.net.URI;
import java.util.Objects;
Expand All @@ -31,7 +31,7 @@
import no.nav.vedtak.isso.config.ServerInfo;
import no.nav.vedtak.sikkerhet.jaspic.OidcTokenHolder;
import no.nav.vedtak.sikkerhet.oidc.IdTokenAndRefreshTokenProvider;
import no.nav.vedtak.sikkerhet.oidc.OidcTokenValidatorProvider;
import no.nav.vedtak.sikkerhet.oidc.OidcTokenValidatorConfig;

@Path("")
public class RelyingPartyCallback {
Expand Down Expand Up @@ -59,7 +59,7 @@ public Response getLogin(@QueryParam("code") String authorizationCode, @QueryPar

var tokens = tokenProvider.getToken(authorizationCode);
var token = tokens.idToken().getToken();
if (!OidcTokenValidatorProvider.instance().getValidator(getIssuser(token)).validate(new OidcTokenHolder(token, false)).isValid()) {
if (!OidcTokenValidatorConfig.instance().getValidator(getIssuer(token)).validate(new OidcTokenHolder(token, false)).isValid()) {
return status(FORBIDDEN).build();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
import no.nav.vedtak.sikkerhet.loginmodule.LoginModuleBase;
import no.nav.vedtak.sikkerhet.oidc.JwtUtil;
import no.nav.vedtak.sikkerhet.oidc.OidcLogin;
import no.nav.vedtak.sikkerhet.oidc.OidcTokenValidatorProvider;
import no.nav.vedtak.sikkerhet.oidc.OidcTokenValidatorConfig;

/**
* <p>
Expand Down Expand Up @@ -70,8 +70,8 @@ public boolean login() throws LoginException {
logger.trace("Enter login method");
ssoToken = getSSOToken();

String issuer = JwtUtil.getIssuser(ssoToken.token());
var tokenValidator = OidcTokenValidatorProvider.instance().getValidator(issuer);
String issuer = JwtUtil.getIssuer(ssoToken.token());
var tokenValidator = OidcTokenValidatorConfig.instance().getValidator(issuer);
logger.trace("Issuer er {}, validator er {}", issuer, tokenValidator);
OidcLogin oidcLogin = new OidcLogin(Optional.of(ssoToken), tokenValidator);
OidcLogin.LoginResult loginResult = oidcLogin.doLogin();
Expand Down Expand Up @@ -169,4 +169,4 @@ protected OidcTokenHolder getSSOToken() throws LoginException {
}
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public static String getJwtBody(String jwt) {
}
}

public static String getIssuser(String jwt) {
public static String getIssuer(String jwt) {
try {
return unvalidatingConsumer.processToClaims(jwt).getIssuer();
} catch (InvalidJwtException | MalformedClaimException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,16 @@

import java.net.URL;

public class OpenIDProviderConfig {
public final class OidcProvider {
private final URL issuer;
private final URL jwks;
private boolean useProxyForJwks;
private final boolean useProxyForJwks;
private final String clientName;
private final int allowedClockSkewInSeconds;
private final boolean skipAudienceValidation;

public OpenIDProviderConfig(URL issuer, URL jwks, boolean useProxyForJwks, String clientName,
int allowedClockSkewInSeconds, boolean skipAudienceValidation) {
public OidcProvider(URL issuer, URL jwks, boolean useProxyForJwks, String clientName,
int allowedClockSkewInSeconds, boolean skipAudienceValidation) {
this.issuer = issuer;
this.jwks = jwks;
this.useProxyForJwks = useProxyForJwks;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
package no.nav.vedtak.sikkerhet.oidc;

import static no.nav.vedtak.sikkerhet.oidc.WellKnownConfigurationHelper.getIssuerFra;
import static no.nav.vedtak.sikkerhet.oidc.WellKnownConfigurationHelper.getJwksFra;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashSet;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

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

import no.nav.foreldrepenger.konfig.Environment;
import no.nav.vedtak.exception.TekniskException;
import no.nav.vedtak.isso.OpenAMHelper;

public final class OidcProviderConfig {
private static final Environment ENV = Environment.current();
private static final Logger LOG = LoggerFactory.getLogger(OidcProviderConfig.class);

public static final String OPEN_AM_WELL_KNOWN_URL = "oidc.open.am.well.known.url";
public static final String OPEN_AM_CLIENT_ID = "oidc.open.am.client.id";
public static final String OPEN_AM_CLIENT_SECRET = "oidc.open.am.client.secret";

private static final String STS_WELL_KNOWN_URL = "oidc.sts.well.known.url";

private static final String LOGINSERVICE_IDPORTEN_DISCOVERY_URL = "loginservice.idporten.discovery.url"; // naiserator
private static final String LOGINSERVICE_CLIENT_ID = "loginservice.idporten.audience"; // naiserator

private static final String AZURE_WELL_KNOWN_URL = "azure.app.well.known.url"; // naiserator
private static final String AZURE_CLIENT_ID = "azure.app.client.id"; // naiserator

private static final String TOKEN_X_WELL_KNOWN_URL = "token.x.well.known.url"; // naiserator
private static final String TOKEN_X_CLIENT_ID = "token.x.client.id"; // naiserator

private static volatile OidcProviderConfig instance; // NOSONAR
private static Set<OidcProvider> providers = new HashSet<>();

private OidcProviderConfig() {
this(init());
}

private OidcProviderConfig(Set<OidcProvider> providers) {
OidcProviderConfig.providers = providers;
}

public static OidcProviderConfig instance() {
var inst= instance;
if (inst == null) {
inst = new OidcProviderConfig();
instance = inst;
}
return inst;
}

public Set<OidcProvider> getOidcProviders() {
return providers;
}

private static Set<OidcProvider> init() {
if (providers.isEmpty()) {
LOG.debug("Henter ID providere.");
return providers = hentConfig();
}
return providers;
}

private static Set<OidcProvider> hentConfig() {
Set<OidcProvider> idProviderConfigs = new HashSet<>();

// OpenAM
idProviderConfigs.add(createOpenAmConfiguration(ENV.getProperty(OPEN_AM_WELL_KNOWN_URL)));

// OIDC STS
idProviderConfigs.add(createStsConfiguration(ENV.getProperty(STS_WELL_KNOWN_URL)));

// Azure
var azureKonfigUrl = ENV.getProperty(AZURE_WELL_KNOWN_URL);
if (azureKonfigUrl != null) {
LOG.debug("Oppretter AzureAD konfig fra '{}'", azureKonfigUrl);
idProviderConfigs.add(createAzureAppConfiguration(azureKonfigUrl));
}

// Loginservice
var loginserviceKonfigUrl = ENV.getProperty(LOGINSERVICE_IDPORTEN_DISCOVERY_URL);
if (loginserviceKonfigUrl != null) {
LOG.debug("Oppretter Loginservice konfig fra '{}'", loginserviceKonfigUrl);
idProviderConfigs.add(createLoginServiceConfiguration(loginserviceKonfigUrl));
}

// TokenX
var tokenxKonfigUrl = ENV.getProperty(TOKEN_X_WELL_KNOWN_URL);
if (tokenxKonfigUrl != null) {
LOG.debug("Oppretter TokenX konfig fra '{}'", tokenxKonfigUrl);
idProviderConfigs.add(createTokenXConfiguration(tokenxKonfigUrl));
}

LOG.info("ID Providere som er tilgjengelig: {}", idProviderConfigs.stream()
.map(OidcProvider::getIssuer)
.map(URL::getHost)
.collect(Collectors.joining(", ")));

return idProviderConfigs;
}

private static OidcProvider createOpenAmConfiguration(String wellKnownUrl) {
LOG.debug("Oppretter OpenAM konfig fra '{}'", wellKnownUrl);
return createConfiguration("oidc_openam",
getIssuerFra(wellKnownUrl).orElse(OpenAMHelper.getIssoIssuerUrl()),
getJwksFra(wellKnownUrl).orElse(OpenAMHelper.getIssoJwksUrl()),
false,
OpenAMHelper.getIssoUserName(),
true);
}

private static OidcProvider createStsConfiguration(String wellKnownUrl) {
LOG.debug("Oppretter OpenAM konfig fra '{}'", wellKnownUrl);
return createConfiguration("oidc_sts",
getIssuerFra(wellKnownUrl).orElse(ENV.getRequiredProperty("oidc.sts.issuer.url")),
getJwksFra(wellKnownUrl).orElse(ENV.getRequiredProperty("oidc.sts.jwks.url")),
false,
"Client name is not used for OIDC STS",
true);
}

private static OidcProvider createAzureAppConfiguration(final String wellKnownUrl) {
return createConfiguration("oidc_azure",
getIssuerFra(wellKnownUrl).orElseThrow(),
getJwksFra(wellKnownUrl).orElseThrow(),
!ENV.isLocal(),
ENV.getRequiredProperty(AZURE_CLIENT_ID),
true);
}

private static OidcProvider createLoginServiceConfiguration(String wellKnownUrl) {
return createConfiguration("oidc_loginservice",
getIssuerFra(wellKnownUrl).orElseThrow(),
getJwksFra(wellKnownUrl).orElseThrow(),
!ENV.isLocal(),
ENV.getRequiredProperty(LOGINSERVICE_CLIENT_ID),
false);
}

private static OidcProvider createTokenXConfiguration(String wellKnownUrl) {
return createConfiguration("oidc_tokenx",
getIssuerFra(wellKnownUrl).orElseThrow(),
getJwksFra(wellKnownUrl).orElseThrow(),
false,
ENV.getRequiredProperty(TOKEN_X_CLIENT_ID),
false);
}

private static OidcProvider createConfiguration(String providerName,
String issuer,
String jwks,
boolean useProxyForJwks,
String clientName,
boolean skipAudienceValidation) {
return Optional.ofNullable(clientName)
.map(c -> new OidcProvider(
url(issuer, "issuer", providerName),
url(jwks, "jwks", providerName),
useProxyForJwks,
c,
30,
skipAudienceValidation))
.orElseThrow();
}

private static URL url(String url, String key, String providerName) {
try {
return new URL(url);
} catch (MalformedURLException e) {
throw new TekniskException("F-644196",
String.format("Syntaksfeil i token validator konfigurasjonen av '%s' for '%s'", key, providerName), e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public class OidcTokenValidator {
private final int allowedClockSkewInSeconds;
private final boolean skipAudienceValidation;

public OidcTokenValidator(OpenIDProviderConfig config) {
public OidcTokenValidator(OidcProvider config) {
this(config.getIssuer().toExternalForm(), new JwksKeyHandlerImpl(config.getJwks(), config.isUseProxyForJwks()), config.getClientName(),
config.getAllowedClockSkewInSeconds(), config.isSkipAudienceValidation());
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,42 +3,42 @@
import java.util.Map;
import java.util.stream.Collectors;

public class OidcTokenValidatorProvider {
public class OidcTokenValidatorConfig {

private static volatile OidcTokenValidatorProvider instance; // NOSONAR
private static volatile OidcTokenValidatorConfig instance; // NOSONAR
private final Map<String, OidcTokenValidator> validators;

private OidcTokenValidatorProvider() {
private OidcTokenValidatorConfig() {
this(init());
}

private OidcTokenValidatorProvider(Map<String, OidcTokenValidator> validators) {
private OidcTokenValidatorConfig(Map<String, OidcTokenValidator> validators) {
this.validators = validators;
}

public static OidcTokenValidatorProvider instance() {
public static OidcTokenValidatorConfig instance() {
var inst= instance;
if (inst == null) {
inst = new OidcTokenValidatorProvider();
inst = new OidcTokenValidatorConfig();
instance = inst;
}
return inst;
}

// For test
static void setValidators(Map<String, OidcTokenValidator> validators) {
instance = new OidcTokenValidatorProvider(validators);
instance = new OidcTokenValidatorConfig(validators);
}

public OidcTokenValidator getValidator(String issuer) {
return validators.get(issuer);
}

private static Map<String, OidcTokenValidator> init() {
var configs = new OpenIDProviderConfigProvider().getConfigs();
return configs.stream().collect(Collectors.toMap(
config -> config.getIssuer().toExternalForm(),
OidcTokenValidator::new));
return OidcProviderConfig.instance().getOidcProviders().stream()
.collect(Collectors.toMap(
config -> config.getIssuer().toExternalForm(),
OidcTokenValidator::new));
}

@Override
Expand Down
Loading

0 comments on commit abcea15

Please sign in to comment.