From 84957a1bb530619900d4a2e88e36273a1d26d651 Mon Sep 17 00:00:00 2001 From: Jens-Otto Larsen <46576810+jolarsen@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:46:09 +0200 Subject: [PATCH] Sanere JA-spi og felles-sikkerhet (#1354) --- felles/pom.xml | 6 - felles/sikkerhet/README.md | 11 - felles/sikkerhet/pom.xml | 68 ----- .../vedtak/sikkerhet/ContextPathHolder.java | 60 ---- .../java/no/nav/vedtak/sikkerhet/README.md | 26 -- .../sikkerhet/context/ContextCleaner.java | 25 -- .../context/containers/BrukerNavnType.java | 53 ---- .../sikkerhet/jaspic/OidcAuthModule.java | 261 ------------------ .../sikkerhet/jaspic/OidcValidation.java | 34 --- .../jaspic/StatelessHttpServletRequest.java | 29 -- .../vedtak/sikkerhet/jaspic/TokenLocator.java | 45 --- .../loginmodule/DummyLoginModule.java | 65 ----- .../loginmodule/LoginConfiguration.java | 17 -- .../LoginContextConfiguration.java | 25 -- .../oidc/OIDCLoginConfiguration.java | 24 -- ...k.sikkerhet.loginmodule.LoginConfiguration | 1 - .../vedtak/sikkerhet/jaspic/KeyStoreTool.java | 89 ------ .../sikkerhet/jaspic/OidcAuthModuleTest.java | 232 ---------------- .../sikkerhet/jaspic/OidcTokenGenerator.java | 75 ----- .../sikkerhet/jaspic/TokenLocatorTest.java | 54 ---- .../src/test/resources/logback-test.xml | 22 -- .../src/test/resources/test-keystore.jks | Bin 2553 -> 0 bytes 22 files changed, 1222 deletions(-) delete mode 100644 felles/sikkerhet/README.md delete mode 100644 felles/sikkerhet/pom.xml delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/ContextPathHolder.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/README.md delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/context/ContextCleaner.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/context/containers/BrukerNavnType.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/OidcAuthModule.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/OidcValidation.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/StatelessHttpServletRequest.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/TokenLocator.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/DummyLoginModule.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/LoginConfiguration.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/LoginContextConfiguration.java delete mode 100644 felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/oidc/OIDCLoginConfiguration.java delete mode 100644 felles/sikkerhet/src/main/resources/META-INF/services/no.nav.vedtak.sikkerhet.loginmodule.LoginConfiguration delete mode 100644 felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/KeyStoreTool.java delete mode 100644 felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/OidcAuthModuleTest.java delete mode 100644 felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/OidcTokenGenerator.java delete mode 100644 felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/TokenLocatorTest.java delete mode 100644 felles/sikkerhet/src/test/resources/logback-test.xml delete mode 100644 felles/sikkerhet/src/test/resources/test-keystore.jks diff --git a/felles/pom.xml b/felles/pom.xml index 062133095..70a27d075 100644 --- a/felles/pom.xml +++ b/felles/pom.xml @@ -15,7 +15,6 @@ testutilities konfig - sikkerhet oidc feil log @@ -97,11 +96,6 @@ felles-db ${project.version} - - no.nav.foreldrepenger.felles.sikkerhet - felles-sikkerhet - ${project.version} - no.nav.foreldrepenger.felles felles-testutilities diff --git a/felles/sikkerhet/README.md b/felles/sikkerhet/README.md deleted file mode 100644 index bf5b35116..000000000 --- a/felles/sikkerhet/README.md +++ /dev/null @@ -1,11 +0,0 @@ -# Sikkerhet -Denne modulen inneholder koden som benyttes for å sette opp: -* Autentisering - * OpenIDConnect - * JASPIC -* Autorisering (ligger pr nå i vl-foreldrepenger, men skal flyttes hit når ferdig) - * ABAC -* Sikkerhetskontekst - * JAAS - -Ytterligere dokumentasjon finnes her: [Sikkerhet](https://confluence.adeo.no/display/SVF/10.1+Tema%3A+Sikkerhet ) diff --git a/felles/sikkerhet/pom.xml b/felles/sikkerhet/pom.xml deleted file mode 100644 index 429171691..000000000 --- a/felles/sikkerhet/pom.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - 4.0.0 - - - no.nav.foreldrepenger.felles - felles - 0.0.0-SNAPSHOT - - - no.nav.foreldrepenger.felles.sikkerhet - felles-sikkerhet - Felles :: Sikkerhet - jar - - - - - no.nav.foreldrepenger.felles - felles-feil - - - no.nav.foreldrepenger.felles - felles-log - - - no.nav.foreldrepenger.felles - felles-mapper - - - no.nav.foreldrepenger.felles - felles-oidc - - - no.nav.foreldrepenger.felles - felles-konfig - - - jakarta.ws.rs - jakarta.ws.rs-api - - - jakarta.authentication - jakarta.authentication-api - - - org.eclipse.jetty.ee10 - jetty-ee10-jaspi - provided - - - org.eclipse.jetty - jetty-server - provided - - - org.eclipse.jetty - jetty-security - provided - - - jakarta.interceptor - jakarta.interceptor-api - - - - diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/ContextPathHolder.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/ContextPathHolder.java deleted file mode 100644 index e8a98720c..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/ContextPathHolder.java +++ /dev/null @@ -1,60 +0,0 @@ -package no.nav.vedtak.sikkerhet; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * Denne eksisterer nå kun pga exp/contract + fp/k9tilbake og cookiepath /k9 - */ -public class ContextPathHolder { - - private static final Logger LOG = LoggerFactory.getLogger(ContextPathHolder.class); - - private static volatile ContextPathHolder instance; // NOSONAR - private final String cookiePath; - private final boolean harSattCookiePath; - - private ContextPathHolder(String cookiePath) { - this.harSattCookiePath = cookiePath != null; - this.cookiePath = validerCookiePath(cookiePath); - } - - public static ContextPathHolder instance() { - var inst = instance; - if (inst == null) { - inst = new ContextPathHolder(null); - instance = inst; - } - return inst; - } - - @Deprecated // K9tilbake trenger denne - @SuppressWarnings("unused") - public static ContextPathHolder instance(@SuppressWarnings("unused") String contextPath, String cookiePath) { - var inst = instance; - if (inst == null) { - inst = new ContextPathHolder(cookiePath); - instance = inst; - } - return inst; - } - - private String validerCookiePath(String cookiePath) { - if (cookiePath == null) { - return "/"; - } - if (!cookiePath.startsWith("/")) { - LOG.warn("CookiePath ({}) er ugyldig som cookiePath, forkaster og bruker default ('/').", cookiePath); - return "/"; - } - return cookiePath; - } - - public String getCookiePath() { - return cookiePath; - } - - public boolean harSattCookiePath() { - return harSattCookiePath; - } -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/README.md b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/README.md deleted file mode 100644 index 6d6ec7da3..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/README.md +++ /dev/null @@ -1,26 +0,0 @@ -Denne modulen dekker JASPI, JAAS og Tokenvalidering -- - -Kode relatert til Context, OIDC-config og Tokenhenting/veksling ligger i felles-oidc - -Sikkerhetskontekst skal hentes fra KontekstHolder, ikke via SubjectHandler - -Kort om hovedkomponentene - -OidcAuthModule -* Inngangsportalen og konfigureres programmatisk i applikasjonenes Jetty-oppsett -* validateRequest får inn alle requests og beskyttede ressurser håndteres av lokal oidcLogin -* Login lager en LoginContext og forsøker en login (validere token, sette context) -* Dersom unathorized: Hvis Bearer -> 401, ellers redirect til OpenAm-login -* Spesialhåndtering av interaktive requests auth-flow, cookies og refresh 2 minutt før tokenutløp -* Stateless connection - ingen session - -LoginModule(s) -* Gjør tokenvalidering og fortsetter prosess basert på resultat -* Vil sørge for en kontekst bestående av Subject, Principal m/identType og token -* Får inn subject og callback i initialize() -* Vanlig OIDC-requests håndteres ved tokenvalidering og setter Authentication for request - -OidcTokenValidator validerer tokens fra ulike issuers og henter jwks til keycache. -Er for tiden en blanding av jose4j og nimbusds (og litt no nav sikkerhet) - diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/context/ContextCleaner.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/context/ContextCleaner.java deleted file mode 100644 index b42e6b4de..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/context/ContextCleaner.java +++ /dev/null @@ -1,25 +0,0 @@ -package no.nav.vedtak.sikkerhet.context; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import no.nav.vedtak.sikkerhet.kontekst.KontekstHolder; - -public class ContextCleaner { - - private static final Logger LOG = LoggerFactory.getLogger(ContextCleaner.class); - - private ContextCleaner() { - } - - public static void enusureCleanContext() { - try { - if (KontekstHolder.harKontekst()) { - LOG.trace("FPFELLES KONTEKST fjernet i ContextCleaner - burde vært fjernet før"); - KontekstHolder.fjernKontekst(); - } - } catch (Exception e) { - LOG.trace("FPFELLES ConClean: kunne ikke fjerne kontekst", e); - } - } -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/context/containers/BrukerNavnType.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/context/containers/BrukerNavnType.java deleted file mode 100644 index 4964812ea..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/context/containers/BrukerNavnType.java +++ /dev/null @@ -1,53 +0,0 @@ -package no.nav.vedtak.sikkerhet.context.containers; - -import java.security.Principal; - -import javax.security.auth.Destroyable; - -import no.nav.vedtak.sikkerhet.kontekst.IdentType; - -public final class BrukerNavnType implements Principal, Destroyable { - - private String uid; - private final IdentType identType; - private boolean destroyed; - - public BrukerNavnType(String uid, IdentType identType) { - this.uid = uid; - this.identType = identType; - } - - public BrukerNavnType(BrukerNavnType brukerNavnType) { - this.uid = brukerNavnType.uid; - this.identType = brukerNavnType.identType; - } - - public IdentType getIdentType() { - return identType; - } - - @Override - public String getName() { - return uid; - } - - - @Override - public void destroy() { - uid = null; - destroyed = true; - } - - @Override - public boolean isDestroyed() { - return destroyed; - } - - @Override - public String toString() { - return getClass().getSimpleName() + "[" + - "identType=" + identType + ", " + - "uid=" + (destroyed ? "destroyed" : uid) + - "]"; - } -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/OidcAuthModule.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/OidcAuthModule.java deleted file mode 100644 index 5447a890f..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/OidcAuthModule.java +++ /dev/null @@ -1,261 +0,0 @@ -package no.nav.vedtak.sikkerhet.jaspic; - -import static jakarta.security.auth.message.AuthStatus.FAILURE; -import static jakarta.security.auth.message.AuthStatus.SEND_CONTINUE; -import static jakarta.security.auth.message.AuthStatus.SEND_SUCCESS; -import static jakarta.security.auth.message.AuthStatus.SUCCESS; - -import java.io.IOException; -import java.time.Instant; -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.callback.Callback; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.callback.UnsupportedCallbackException; -import javax.security.auth.login.Configuration; -import javax.security.auth.login.LoginContext; -import javax.security.auth.login.LoginException; - -import org.eclipse.jetty.ee10.security.jaspi.JaspiMessageInfo; -import org.eclipse.jetty.server.Response; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.slf4j.MDC; - -import jakarta.security.auth.message.AuthStatus; -import jakarta.security.auth.message.MessageInfo; -import jakarta.security.auth.message.MessagePolicy; -import jakarta.security.auth.message.callback.CallerPrincipalCallback; -import jakarta.security.auth.message.config.ServerAuthContext; -import jakarta.security.auth.message.module.ServerAuthModule; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import no.nav.vedtak.exception.TekniskException; -import no.nav.vedtak.log.mdc.MDCOperations; -import no.nav.vedtak.sikkerhet.context.containers.BrukerNavnType; -import no.nav.vedtak.sikkerhet.kontekst.KontekstHolder; -import no.nav.vedtak.sikkerhet.kontekst.RequestKontekst; -import no.nav.vedtak.sikkerhet.loginmodule.LoginContextConfiguration; -import no.nav.vedtak.sikkerhet.oidc.config.ConfigProvider; -import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken; -import no.nav.vedtak.sikkerhet.oidc.token.TokenString; -import no.nav.vedtak.sikkerhet.oidc.validator.JwtUtil; - -/** - * Stjålet mye fra https://github.com/omnifaces/omnisecurity - *

- * Klassen er og må være thread-safe da den vil brukes til å kalle på subjects - * samtidig. Se {@link ServerAuthModule}. Skal derfor ikke inneholde felter som - * holder Subject, token eller andre parametere som kommer med en request eller - * session. - */ -public class OidcAuthModule implements ServerAuthModule { - - private static final String OIDC_LOGIN_CONFIG = "OIDC"; - private static final Logger LOG = LoggerFactory.getLogger(OidcAuthModule.class); - - private static final Class[] SUPPORTED_MESSAGE_TYPES = new Class[]{HttpServletRequest.class, HttpServletResponse.class}; - - private final TokenLocator tokenLocator; - private final Configuration loginConfiguration; - - private CallbackHandler containerCallbackHandler; - - public OidcAuthModule() { - this.tokenLocator = new TokenLocator(); - this.loginConfiguration = new LoginContextConfiguration(); - } - - /** - * used for unit-testing - */ - OidcAuthModule(TokenLocator tokenLocator, Configuration loginConfiguration) { - this.tokenLocator = tokenLocator; - this.loginConfiguration = loginConfiguration; - } - - @SuppressWarnings("rawtypes") - @Override - public void initialize(MessagePolicy requestPolicy, MessagePolicy responsePolicy, CallbackHandler handler, Map options) { - this.containerCallbackHandler = handler; - } - - @SuppressWarnings("rawtypes") - @Override - public Class[] getSupportedMessageTypes() { - return SUPPORTED_MESSAGE_TYPES; - } - - @Override - public AuthStatus validateRequest(MessageInfo messageInfo, Subject clientSubject, Subject serviceSubject) { - HttpServletRequest originalRequest = (HttpServletRequest) messageInfo.getRequestMessage(); - setCallAndConsumerId(originalRequest); - validateCleanSubjectAndKontekst(clientSubject); - // Skipp sjekk på unprotected siden NPE i JaspiMessageInfo/getMap. Legg unprotected i web.xml - AuthStatus authStatus = handleProtectedResource(clientSubject, originalRequest); - - if (FAILURE.equals(authStatus)) { - // Vurder om trengs whitelisting av oppslag mot isAlive/isReady/metrics gitt oppførsel i prod - app må registrere unprotected - // Sjekk av whitelist/unprotected mot HttpServletRequest / getPathInfo må foregå før valg av protected/unprotected - try { - if (messageInfo instanceof JaspiMessageInfo mi) { - Response.writeError(mi.getBaseRequest(), mi.getBaseResponse(), mi.getCallback(), 401); - } else { - return FAILURE; // Vil gi 403 - } - } catch (Exception e) { - throw new TekniskException("F-396795", "Klarte ikke å sende respons", e); // Gir 500 - } - return SEND_CONTINUE; // SEND_CONTINUE sørger for svar med 401. (SEND_)FAILURE gir 403 - } - - if (SUCCESS.equals(authStatus)) { - messageInfo.setRequestMessage(new StatelessHttpServletRequest((HttpServletRequest) messageInfo.getRequestMessage())); - } - return authStatus; - } - - protected void validateCleanSubjectAndKontekst(Subject subject) { - // Skal vel egentlig ikke skje men logg for ordens skyld - var sluttbrukere = Optional.ofNullable(subject).map(Subject::getPrincipals).orElse(Set.of()).stream() - .filter(BrukerNavnType.class::isInstance) - .toList(); - if (!sluttbrukere.isEmpty()) { - LOG.trace("FPFELLES KONTEKST validateRequest: clientSubject inneholdt brukerNavnType {}", sluttbrukere); - sluttbrukere.forEach(s -> subject.getPrincipals().remove(s)); - } - - if (KontekstHolder.harKontekst()) { - final var kontekst = KontekstHolder.getKontekst(); - LOG.trace("FPFELLES KONTEKST validateRequest: Tråden inneholdt allerede kontekst for context {} bruker {} identType {}", - kontekst.getContext(), kontekst.getUid(), kontekst.getIdentType()); - KontekstHolder.fjernKontekst(); - } - } - - public void setCallAndConsumerId(HttpServletRequest request) { - String callId = Optional.ofNullable(request.getHeader(MDCOperations.HTTP_HEADER_CALL_ID)) - .orElseGet(() -> request.getHeader(MDCOperations.HTTP_HEADER_ALT_CALL_ID)); - if (callId != null) { - MDCOperations.putCallId(callId); - } else { - MDCOperations.putCallId(); - } - - String consumerId = request.getHeader(MDCOperations.HTTP_HEADER_CONSUMER_ID); - if (consumerId != null) { - MDCOperations.putConsumerId(consumerId); - } - } - - protected AuthStatus handleProtectedResource(Subject clientSubject, HttpServletRequest request) { - // Get token - var oidcToken = tokenLocator.getToken(request); - if (oidcToken.isEmpty()) { - return FAILURE; - } - var claims = oidcToken.map(TokenString::token).map(JwtUtil::getClaims); - var configuration = claims.map(JwtUtil::getIssuer).flatMap(ConfigProvider::getOpenIDConfiguration); - if (configuration.isEmpty()) { - return FAILURE; - } - - var expiresAt = claims.map(JwtUtil::getExpirationTime).orElseGet(() -> Instant.now().plusSeconds(300)); - var token = new OpenIDToken(configuration.get().type(), OpenIDToken.OIDC_DEFAULT_TOKEN_TYPE, oidcToken.get(), null, expiresAt.toEpochMilli()); - - var valideringsResultat = OidcValidation.validerToken(token); - var sluttbruker = valideringsResultat.isValid() ? valideringsResultat.subject() : null; - if (sluttbruker != null) { - KontekstHolder.setKontekst(RequestKontekst.forRequest(sluttbruker.uid(), sluttbruker.shortUid(), sluttbruker.identType(), token, sluttbruker.grupper())); - } else { - return FAILURE; - } - - // Dummy - finnes kun pga Jakarta Authentication 3.0 kap 6 LoginModule Bridge Profile. - LoginContext loginContext = createLoginContext(clientSubject); - try { - loginContext.login(); - } catch (LoginException e) { - return FAILURE; - } - - clientSubject.getPrincipals().add(new BrukerNavnType(sluttbruker.uid(), sluttbruker.identType())); - - MDCOperations.putUserId(sluttbruker.uid()); - if (MDCOperations.getConsumerId() == null) { - MDCOperations.putConsumerId(sluttbruker.uid()); - } - - // Handle result - return notifyContainerAboutLogin(clientSubject, sluttbruker.uid()); - } - - private LoginContext createLoginContext(Subject clientSubject) { - class NotUsedCallbackHandler implements CallbackHandler { - @Override - public void handle(Callback[] callbacks) throws UnsupportedCallbackException { - if (callbacks.length > 0) { - // Should never happen - throw new UnsupportedCallbackException(callbacks[0], "OIDC LoginModule skal ikke kalle tilbake"); - } - } - } - - CallbackHandler callbackHandler = new NotUsedCallbackHandler(); - try { - return new LoginContext(OIDC_LOGIN_CONFIG, clientSubject, callbackHandler, loginConfiguration); - } catch (LoginException le) { - throw new TekniskException("F-651753", String.format("Kunne ikke finne konfigurasjonen for %s", OIDC_LOGIN_CONFIG), le); - } - } - - /** - * Asks the container to register the given username. - *

- * Note that after this call returned, the authenticated identity will not be - * immediately active. This will only take place (should not errors occur) after - * the {@link ServerAuthContext} or {@link ServerAuthModule} in which this call - * takes place return control back to the runtime. - *

- * As a convenience this method returns SUCCESS, so this method can be used in - * one fluent return statement from an auth module. - * - * @param username the user name that will become the caller principal - * @return {@link AuthStatus#SUCCESS} - */ - private AuthStatus notifyContainerAboutLogin(Subject clientSubject, String username) { - try { - containerCallbackHandler.handle(new Callback[]{new CallerPrincipalCallback(clientSubject, username)}); - } catch (IOException | UnsupportedCallbackException e) { - // Should not happen - throw new IllegalStateException(e); - } - return SUCCESS; - } - - @Override - public AuthStatus secureResponse(MessageInfo messageInfo, Subject serviceSubject) { - if (KontekstHolder.harKontekst()) { - KontekstHolder.fjernKontekst(); - } else { - LOG.trace("FPFELLES KONTEKST fant ikke kontekst som forventet i secureResponse"); - } - MDC.clear(); - return SEND_SUCCESS; - } - - @Override - public void cleanSubject(MessageInfo messageInfo, Subject subject) { - if (KontekstHolder.harKontekst()) { - LOG.trace("FPFELLES KONTEKST hadde kontekst ved cleanSubject"); - KontekstHolder.fjernKontekst(); - } - if (subject != null) { - subject.getPrincipals().clear(); - } - } - -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/OidcValidation.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/OidcValidation.java deleted file mode 100644 index 73a66f7ad..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/OidcValidation.java +++ /dev/null @@ -1,34 +0,0 @@ -package no.nav.vedtak.sikkerhet.jaspic; - -import java.util.Set; - -import no.nav.vedtak.sikkerhet.kontekst.Groups; -import no.nav.vedtak.sikkerhet.kontekst.IdentType; -import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken; -import no.nav.vedtak.sikkerhet.oidc.validator.OidcTokenValidatorConfig; - -public final class OidcValidation { - - private OidcValidation() { - } - - public record SluttBruker(String uid, String shortUid, IdentType identType, Set grupper) {} - - public record Resultat(boolean isValid, SluttBruker subject, String errorMessage) {} - - public static Resultat validerToken(OpenIDToken openIDToken) { - if (openIDToken == null || openIDToken.provider() == null) { - return new Resultat(false, null, null); - } - var tokenValidator = OidcTokenValidatorConfig.instance().getValidator(openIDToken.provider()); - var validateResult = tokenValidator.validate(openIDToken.primary()); - if (validateResult.isValid()) { - return new Resultat(true, new SluttBruker(validateResult.getSubject(), validateResult.getCompactSubject(), - validateResult.getIdentType(), validateResult.getGrupper()),null); - } - return new Resultat(false, null, validateResult.getErrorMessage()); - } - - - -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/StatelessHttpServletRequest.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/StatelessHttpServletRequest.java deleted file mode 100644 index 0ea9c6670..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/StatelessHttpServletRequest.java +++ /dev/null @@ -1,29 +0,0 @@ -package no.nav.vedtak.sikkerhet.jaspic; - -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletRequestWrapper; -import jakarta.servlet.http.HttpSession; - -/** - * Wraps the request in a object that throws an {@link IllegalArgumentException} - * when invoking getSession or getSession(true) - */ -public class StatelessHttpServletRequest extends HttpServletRequestWrapper { - - public StatelessHttpServletRequest(HttpServletRequest request) { - super(request); - } - - @Override - public HttpSession getSession() { - return getSession(true); - } - - @Override - public HttpSession getSession(boolean create) { - if (create) { - throw new IllegalArgumentException("This is a stateless application so creating a Session is forbidden."); - } - return super.getSession(create); - } -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/TokenLocator.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/TokenLocator.java deleted file mode 100644 index 530a3b293..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/jaspic/TokenLocator.java +++ /dev/null @@ -1,45 +0,0 @@ -package no.nav.vedtak.sikkerhet.jaspic; - -import no.nav.vedtak.sikkerhet.ContextPathHolder; -import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken; -import no.nav.vedtak.sikkerhet.oidc.token.TokenString; - -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; - -import java.util.Arrays; -import java.util.Optional; - -class TokenLocator { - - static final String ID_TOKEN_COOKIE_NAME = "ID_token"; - - public Optional getToken(HttpServletRequest request) { - return getTokenFromHeader(request).or(() -> getCookie(request, ID_TOKEN_COOKIE_NAME)); - } - - private Optional getCookie(HttpServletRequest request, String cookieName) { - if (!ContextPathHolder.instance().harSattCookiePath() || request.getCookies() == null) { - return Optional.empty(); - } - var cookiePath = ContextPathHolder.instance().getCookiePath(); - return Arrays.stream(request.getCookies()) - .filter(c -> c.getValue() != null) - .filter(c -> cookieName.equalsIgnoreCase(c.getName())) - .filter(c -> cookiePath.equalsIgnoreCase(c.getPath())) - .findFirst() - .or(() -> Arrays.stream(request.getCookies()) - .filter(c -> c.getValue() != null) - .filter(c -> cookieName.equalsIgnoreCase(c.getName())) - .findFirst()) - .map(Cookie::getValue) - .map(TokenString::new); - } - - private Optional getTokenFromHeader(HttpServletRequest request) { - String headerValue = request.getHeader("Authorization"); - return headerValue != null && headerValue.startsWith(OpenIDToken.OIDC_DEFAULT_TOKEN_TYPE) ? Optional.of( - new TokenString(headerValue.substring(OpenIDToken.OIDC_DEFAULT_TOKEN_TYPE.length()))) : Optional.empty(); - } - -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/DummyLoginModule.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/DummyLoginModule.java deleted file mode 100644 index 7afb23d82..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/DummyLoginModule.java +++ /dev/null @@ -1,65 +0,0 @@ -package no.nav.vedtak.sikkerhet.loginmodule; - -import java.util.Map; -import java.util.Optional; -import java.util.Set; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.LoginException; -import javax.security.auth.spi.LoginModule; - -import no.nav.vedtak.sikkerhet.context.containers.BrukerNavnType; -import no.nav.vedtak.sikkerhet.kontekst.KontekstHolder; - -/** - *

- * Dummy LoginModule - finnes kun pga Jakarta Authentication 3.0 kap 6 LoginModule Bridge Profile - * Autentisering foregår i SAM. Usikker om denne overhodet trengs - *

- */ -public class DummyLoginModule implements LoginModule { - - private Subject subject; - - public DummyLoginModule() { - // NOOP - } - - - @Override - public void initialize(Subject subject, CallbackHandler callbackHandler, Map sharedState, Map options) { - this.subject = subject; - } - - @Override - public boolean login() throws LoginException { - return true; - } - - @Override - public final boolean commit() { - return true; - } - - @Override - public final boolean abort() { - return this.logout(); - } - - @Override - public final boolean logout() { - ryddKontekster(); - return true; - } - - private void ryddKontekster() { - if (KontekstHolder.harKontekst()) { - KontekstHolder.fjernKontekst(); - } - Optional.ofNullable(subject).map(Subject::getPrincipals).orElseGet(Set::of).stream() - .filter(BrukerNavnType.class::isInstance) - .forEach(p -> subject.getPrincipals().remove(p)); - } - -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/LoginConfiguration.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/LoginConfiguration.java deleted file mode 100644 index 960392273..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/LoginConfiguration.java +++ /dev/null @@ -1,17 +0,0 @@ -package no.nav.vedtak.sikkerhet.loginmodule; - -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.Configuration; - -/** - * Pluggbart interface for å legge til login moduler vha ServiceLoader. - */ -public interface LoginConfiguration { - - /** - * Navn. Matcher name for indeksering av {@link Configuration}. - */ - String getName(); - - AppConfigurationEntry[] getAppConfigurationEntry(); -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/LoginContextConfiguration.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/LoginContextConfiguration.java deleted file mode 100644 index 91f39ede0..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/LoginContextConfiguration.java +++ /dev/null @@ -1,25 +0,0 @@ -package no.nav.vedtak.sikkerhet.loginmodule; - -import java.util.Map; -import java.util.ServiceLoader; -import java.util.ServiceLoader.Provider; -import java.util.stream.Collectors; - -import javax.security.auth.login.AppConfigurationEntry; -import javax.security.auth.login.Configuration; - -public class LoginContextConfiguration extends Configuration { - - private static final Map CONFIGS = ServiceLoader.load(LoginConfiguration.class) - .stream() - .map(Provider::get) - .collect(Collectors.toMap(LoginConfiguration::getName, LoginConfiguration::getAppConfigurationEntry)); - - @Override - public AppConfigurationEntry[] getAppConfigurationEntry(String name) { - if (!CONFIGS.containsKey(name)) { - throw new IllegalArgumentException("Har ikke konfigurasjon for: " + name); - } - return CONFIGS.get(name); - } -} diff --git a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/oidc/OIDCLoginConfiguration.java b/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/oidc/OIDCLoginConfiguration.java deleted file mode 100644 index 1f1d3769d..000000000 --- a/felles/sikkerhet/src/main/java/no/nav/vedtak/sikkerhet/loginmodule/oidc/OIDCLoginConfiguration.java +++ /dev/null @@ -1,24 +0,0 @@ -package no.nav.vedtak.sikkerhet.loginmodule.oidc; - -import java.util.Map; - -import javax.security.auth.login.AppConfigurationEntry; - -import no.nav.vedtak.sikkerhet.loginmodule.LoginConfiguration; - -public class OIDCLoginConfiguration implements LoginConfiguration { - - private static final AppConfigurationEntry[] OIDC_CONFIGURATION = new AppConfigurationEntry[]{new AppConfigurationEntry( - "no.nav.vedtak.sikkerhet.loginmodule.DummyLoginModule", AppConfigurationEntry.LoginModuleControlFlag.REQUISITE, Map.of())}; - - @Override - public String getName() { - return "OIDC"; - } - - @Override - public AppConfigurationEntry[] getAppConfigurationEntry() { - return OIDC_CONFIGURATION; - } - -} diff --git a/felles/sikkerhet/src/main/resources/META-INF/services/no.nav.vedtak.sikkerhet.loginmodule.LoginConfiguration b/felles/sikkerhet/src/main/resources/META-INF/services/no.nav.vedtak.sikkerhet.loginmodule.LoginConfiguration deleted file mode 100644 index b658b06e5..000000000 --- a/felles/sikkerhet/src/main/resources/META-INF/services/no.nav.vedtak.sikkerhet.loginmodule.LoginConfiguration +++ /dev/null @@ -1 +0,0 @@ -no.nav.vedtak.sikkerhet.loginmodule.oidc.OIDCLoginConfiguration diff --git a/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/KeyStoreTool.java b/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/KeyStoreTool.java deleted file mode 100644 index 3458ff3b3..000000000 --- a/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/KeyStoreTool.java +++ /dev/null @@ -1,89 +0,0 @@ -package no.nav.vedtak.sikkerhet.jaspic; - -import java.io.IOException; -import java.io.InputStream; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.PublicKey; -import java.security.UnrecoverableEntryException; -import java.security.cert.Certificate; -import java.security.cert.CertificateException; -import java.security.interfaces.RSAPublicKey; - -import org.jose4j.base64url.Base64Url; -import org.jose4j.jwk.PublicJsonWebKey; -import org.jose4j.jwk.RsaJsonWebKey; -import org.jose4j.lang.JoseException; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class KeyStoreTool { - - private static RsaJsonWebKey jwk = null; - - private static final Logger LOG = LoggerFactory.getLogger(KeyStoreTool.class); - - static { - - PublicKey myPublicKey; - PrivateKey myPrivateKey; - char[] keystorePassword = getKeyStoreAndKeyPassword(); - String keyAndCertAlias = getKeyAndCertAlias(); - - try (InputStream keystoreFile = KeyStoreTool.class.getResourceAsStream("/test-keystore.jks")) { - KeyStore ks = KeyStore.getInstance("JKS"); - ks.load(keystoreFile, keystorePassword); - - KeyStore.ProtectionParameter protParam = new KeyStore.PasswordProtection(keystorePassword); - KeyStore.PrivateKeyEntry pk = (KeyStore.PrivateKeyEntry) ks.getEntry(keyAndCertAlias, protParam); - myPrivateKey = pk.getPrivateKey(); - Certificate cert = ks.getCertificate(keyAndCertAlias); - myPublicKey = cert.getPublicKey(); - - //KeyStoreTool.keystore = ks; - } catch (KeyStoreException | NoSuchAlgorithmException | CertificateException | IOException | UnrecoverableEntryException e) { - LOG.error("Error during loading of keystore. Do you have your keystore in order, soldier?", e); - throw new RuntimeException(e); - } - - try { - jwk = (RsaJsonWebKey) PublicJsonWebKey.Factory.newPublicJwk(myPublicKey); - jwk.setPrivateKey(myPrivateKey); - jwk.setKeyId("1"); - } catch (JoseException e) { - LOG.error("Error during init of JWK: " + e); - throw new RuntimeException(e); - } - - } - - public static char[] getKeyStoreAndKeyPassword() { - return "changeit".toCharArray(); - } - - public static String getKeyAndCertAlias() { - return System.getProperty("no.nav.modig.security.appkey", "app-key"); - } - - public static RsaJsonWebKey getJsonWebKey() { - return jwk; - } - - public static String getJwks() { - String kty = "RSA"; - String kid = "1"; - String use = "sig"; - String alg = "RS256"; - String e = Base64Url.encode(jwk.getRsaPublicKey().getPublicExponent().toByteArray()); - RSAPublicKey publicKey = (RSAPublicKey) jwk.getPublicKey(); - - byte[] bytes = publicKey.getModulus().toByteArray(); - String n = Base64Url.encode(bytes); - - return String.format( - "{\"keys\":[{" + "\"kty\":\"%s\"," + "\"alg\":\"%s\"," + "\"use\":\"%s\"," + "\"kid\":\"%s\"," + "\"n\":\"%s\"," + "\"e\":\"%s\"" + "}]}", - kty, alg, use, kid, n, e); - } -} diff --git a/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/OidcAuthModuleTest.java b/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/OidcAuthModuleTest.java deleted file mode 100644 index 0f0356d14..000000000 --- a/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/OidcAuthModuleTest.java +++ /dev/null @@ -1,232 +0,0 @@ -package no.nav.vedtak.sikkerhet.jaspic; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import java.util.HashMap; -import java.util.Map; -import java.util.Optional; - -import javax.security.auth.Subject; -import javax.security.auth.callback.CallbackHandler; -import javax.security.auth.login.Configuration; - -import org.eclipse.jetty.ee10.security.jaspi.JaspiMessageInfo; -import org.eclipse.jetty.http.HttpFields; -import org.eclipse.jetty.http.HttpVersion; -import org.eclipse.jetty.server.ConnectionMetaData; -import org.eclipse.jetty.server.Context; -import org.eclipse.jetty.server.Request; -import org.eclipse.jetty.server.Response; -import org.jose4j.json.JsonUtil; -import org.jose4j.jwt.NumericDate; -import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; -import org.mockito.Mockito; - -import jakarta.security.auth.message.AuthStatus; -import jakarta.security.auth.message.MessageInfo; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; -import no.nav.vedtak.sikkerhet.kontekst.IdentType; -import no.nav.vedtak.sikkerhet.loginmodule.LoginContextConfiguration; -import no.nav.vedtak.sikkerhet.oidc.config.AzureProperty; -import no.nav.vedtak.sikkerhet.oidc.config.OpenIDProvider; -import no.nav.vedtak.sikkerhet.oidc.config.impl.WellKnownConfigurationHelper; -import no.nav.vedtak.sikkerhet.oidc.token.OpenIDToken; -import no.nav.vedtak.sikkerhet.oidc.token.TokenString; -import no.nav.vedtak.sikkerhet.oidc.validator.OidcTokenValidator; -import no.nav.vedtak.sikkerhet.oidc.validator.OidcTokenValidatorConfig; -import no.nav.vedtak.sikkerhet.oidc.validator.OidcTokenValidatorResult; - -class OidcAuthModuleTest { - - private final OidcTokenValidator tokenValidator = Mockito.mock(OidcTokenValidator.class); - private final TokenLocator tokenLocator = Mockito.mock(TokenLocator.class); - private final CallbackHandler callbackHandler = Mockito.mock(CallbackHandler.class); - private final Configuration configuration = new LoginContextConfiguration(); - - private final OidcAuthModule authModule = new OidcAuthModule(tokenLocator, configuration); - private final HttpServletRequest request = Mockito.mock(HttpServletRequest.class); - private final HttpServletResponse response = Mockito.mock(HttpServletResponse.class); - - private final Request requestBase = Mockito.mock(Request.class); - private final Response responseBase = Mockito.mock(Response.class); - private final ConnectionMetaData connMetaData = Mockito.mock(ConnectionMetaData.class); - private final Context context = Mockito.mock(Context.class); - - private Subject subject = new Subject(); - private Subject serviceSubject = new Subject(); - - @BeforeEach - public void setUp() { - WellKnownConfigurationHelper.unsetWellKnownConfig(); - authModule.initialize(null, null, callbackHandler, null); - - System.setProperty(AzureProperty.AZURE_APP_WELL_KNOWN_URL.name(), - OidcTokenGenerator.ISSUER + "/" + WellKnownConfigurationHelper.STANDARD_WELL_KNOWN_PATH); - System.setProperty(AzureProperty.AZURE_APP_CLIENT_ID.name(), "OIDC"); - System.setProperty(AzureProperty.AZURE_OPENID_CONFIG_ISSUER.name(), OidcTokenGenerator.ISSUER); - System.setProperty(AzureProperty.AZURE_OPENID_CONFIG_JWKS_URI.name(), OidcTokenGenerator.ISSUER + "/jwks_uri"); - System.setProperty("systembruker.username", "JUnit Test"); - - Map testData = Map.of("issuer", OidcTokenGenerator.ISSUER, AzureProperty.AZURE_OPENID_CONFIG_JWKS_URI.name(), - OidcTokenGenerator.ISSUER + "/jwks_uri"); - WellKnownConfigurationHelper.setWellKnownConfig(OidcTokenGenerator.ISSUER + "/" + WellKnownConfigurationHelper.STANDARD_WELL_KNOWN_PATH, - JsonUtil.toJson(testData)); - OidcTokenValidatorConfig.addValidator(OpenIDProvider.AZUREAD, tokenValidator); - } - - @Test - void skal_ikke_slippe_gjennom_forespørsel_men_svare_med_401_etter_beskyttet_ressurs_når_forespørselen_ikke_har_med_id_token() throws Exception { - when(request.getHeader("Accept")).thenReturn("application/json"); - MessageInfo request = createRequestForProtectedResource(); - - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.empty()); - - AuthStatus result = authModule.validateRequest(request, subject, serviceSubject); - assertThat(result).isEqualTo(AuthStatus.SEND_CONTINUE); - verify(responseBase).setStatus(401); - } - - @Test - void skal_sende_401_for_ugyldig_Authorization_header() throws Exception { - var utløptIdToken = getUtløptToken(); - - when(request.getHeader("Accept")).thenReturn(null); - when(request.getHeader("Authorization")).thenReturn(OpenIDToken.OIDC_DEFAULT_TOKEN_TYPE + utløptIdToken); - MessageInfo request = createRequestForProtectedResource(); - - - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.of(utløptIdToken)); - when(tokenValidator.validate(any())).thenReturn(OidcTokenValidatorResult.invalid("Tokenet er ikke gyldig")); - - AuthStatus result = authModule.validateRequest(request, subject, serviceSubject); - assertThat(result).isEqualTo(AuthStatus.SEND_CONTINUE); - verify(responseBase).setStatus(401); - } - - @Test - void skal_ikke_slippe_gjennom_forespørsel_men_svare_med_redirect_til_openam_etter_beskyttet_ressurs_når_forespørselen_ikke_har_med_id_token() throws Exception { - when(request.getHeader("Accept")).thenReturn("*/*"); - MessageInfo request = createRequestForProtectedResource(); - - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.empty()); - - AuthStatus result = authModule.validateRequest(request, subject, serviceSubject); - assertThat(result).isEqualTo(AuthStatus.SEND_CONTINUE); - verify(responseBase).setStatus(401); - } - - @Test - void skal_slippe_gjennom_forespørsel_etter_beskyttet_ressurs_når_forespørselen_har_med_id_token_som_validerer() throws Exception { - MessageInfo request = createRequestForProtectedResource(); - - var gyldigIdToken = getGyldigToken(); - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.of(gyldigIdToken)); - when(tokenValidator.validate(gyldigIdToken)).thenReturn( - OidcTokenValidatorResult.valid("demo", IdentType.utledIdentType("demo"), System.currentTimeMillis() / 1000 + 121)); - - AuthStatus result = authModule.validateRequest(request, subject, serviceSubject); - assertThat(result).isEqualTo(AuthStatus.SUCCESS); - } - - @Test - void skal_ikke_slippe_gjennom_forespørsel_etter_beskyttet_ressurs_når_forespørselen_har_med_et_utløpt_id_token_og_ikke_noe_refresh_token() throws Exception { - MessageInfo request = createRequestForProtectedResource(); - - var ugyldigToken = getUtløptToken(); - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.of(ugyldigToken)); - when(tokenValidator.validate(any())).thenReturn(OidcTokenValidatorResult.invalid("Tokenet er ikke gyldig")); - - AuthStatus result = authModule.validateRequest(request, subject, serviceSubject); - assertThat(result).isEqualTo(AuthStatus.SEND_CONTINUE); - verify(responseBase).setStatus(401); - } - - @Test - void skal_ikke_slippe_gjennom_forespørsel_og_svare_med_redirect_når_det_ikke_er_satt_application_json() throws Exception { - MessageInfo request = createRequestForProtectedResource(); - - var ugyldigToken = getUtløptToken(); - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.of(ugyldigToken)); - when(tokenValidator.validate(any())).thenReturn(OidcTokenValidatorResult.invalid("Tokenet er ikke gyldig")); - - AuthStatus result = authModule.validateRequest(request, subject, serviceSubject); - assertThat(result).isEqualTo(AuthStatus.SEND_CONTINUE); - verify(responseBase).setStatus(401); - } - - @Test - void skal_ikke_slippe_gjennom_forespørsel_etter_beskyttet_ressurs_når_forespørselen_har_med_et_utløpt_id_token_og_ikke_klarer_å_hente_nytt_token_med_refresh_token() throws Exception { - MessageInfo request = createRequestForProtectedResource(); - - var ugyldigToken = getUtløptToken(); - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.of(ugyldigToken)); - when(tokenValidator.validate(ugyldigToken)).thenReturn(OidcTokenValidatorResult.invalid("Tokenet er ikke gyldig")); - - AuthStatus result = authModule.validateRequest(request, subject, serviceSubject); - - assertThat(result).isEqualTo(AuthStatus.SEND_CONTINUE); - verify(responseBase).setStatus(401); - } - - - @Test - void skal_slippe_gjennom_token_tilstrekkelig_levetid_til_å_brukes_til_kall_til_andre_tjenester() throws Exception { - MessageInfo request = createRequestForProtectedResource(); - - int sekunderGjenståendeGyldigTid = 125; - - var gyldigIdToken = getGyldigToken(); - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.of(gyldigIdToken)); - when(tokenValidator.validate(gyldigIdToken)).thenReturn(OidcTokenValidatorResult.valid("demo", IdentType.utledIdentType("demo"), - System.currentTimeMillis() / 1000 + sekunderGjenståendeGyldigTid)); - - var result = authModule.validateRequest(request, subject, serviceSubject); - - assertThat(result).isEqualTo(AuthStatus.SUCCESS); - } - - @Test - void skal_slippe_gjennom_token_tilstrekkelig_levetid_til_å_brukes_til_kall_til_andre_tjenester_selv_om_kortere_enn_gammel_grense() throws Exception { - MessageInfo request = createRequestForProtectedResource(); - - int sekunderGjenståendeGyldigTid = 115; - - var gyldigIdToken = getGyldigToken(); - when(tokenLocator.getToken(any(HttpServletRequest.class))).thenReturn(Optional.of(gyldigIdToken)); - when(tokenValidator.validate(gyldigIdToken)).thenReturn(OidcTokenValidatorResult.valid("demo", IdentType.utledIdentType("demo"), - System.currentTimeMillis() / 1000 + sekunderGjenståendeGyldigTid)); - - var result = authModule.validateRequest(request, subject, serviceSubject); - assertThat(result).isEqualTo(AuthStatus.SUCCESS); - } - - private MessageInfo createRequestForProtectedResource() { - when(requestBase.getConnectionMetaData()).thenReturn(connMetaData); - when(connMetaData.getHttpVersion()).thenReturn(HttpVersion.HTTP_2); - when(requestBase.getContext()).thenReturn(context); - when(responseBase.getHeaders()).thenReturn(HttpFields.build()); - var messageInfo = Mockito.mock(JaspiMessageInfo.class); - Map properties = new HashMap<>(); - when(messageInfo.getMap()).thenReturn(properties); - when(messageInfo.getRequestMessage()).thenReturn(request); - when(messageInfo.getResponseMessage()).thenReturn(response); - when(messageInfo.getBaseResponse()).thenReturn(responseBase); - when(messageInfo.getBaseRequest()).thenReturn(requestBase); - when(messageInfo.getCallback()).thenReturn(null); - return messageInfo; - } - - private static TokenString getGyldigToken() { - return new OidcTokenGenerator().createCookieTokenHolder(); - } - - private static TokenString getUtløptToken() { - return new OidcTokenGenerator().withExpiration(NumericDate.fromMilliseconds(System.currentTimeMillis() - 1)).createCookieTokenHolder(); - } - -} diff --git a/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/OidcTokenGenerator.java b/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/OidcTokenGenerator.java deleted file mode 100644 index df7fd496e..000000000 --- a/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/OidcTokenGenerator.java +++ /dev/null @@ -1,75 +0,0 @@ -package no.nav.vedtak.sikkerhet.jaspic; - -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import org.jose4j.jwk.RsaJsonWebKey; -import org.jose4j.jws.AlgorithmIdentifiers; -import org.jose4j.jws.JsonWebSignature; -import org.jose4j.jwt.JwtClaims; -import org.jose4j.jwt.NumericDate; -import org.jose4j.lang.JoseException; - -import no.nav.vedtak.sikkerhet.oidc.token.TokenString; - -public class OidcTokenGenerator { - public static final String ISSUER = "https://foo.bar.adeo.no/azure/oauth2"; - private List aud = Collections.singletonList("OIDC"); - private NumericDate expiration = NumericDate.fromSeconds(NumericDate.now().getValue() + 3600); - private String issuer = ISSUER; - private NumericDate issuedAt = NumericDate.now(); - private String subject = "demo"; - private String kid; - - private Map additionalClaims = new HashMap<>(); - - public OidcTokenGenerator() { - additionalClaims.put("azp", "OIDC"); - } - - public OidcTokenGenerator withExpiration(NumericDate expiration) { - this.expiration = expiration; - return this; - } - - - public TokenString createCookieTokenHolder() { - return new TokenString(create()); - } - - public String create() { - if (kid == null) { - kid = KeyStoreTool.getJsonWebKey().getKeyId(); - } - - JwtClaims claims = new JwtClaims(); - claims.setIssuer(issuer); - claims.setExpirationTime(expiration); - claims.setGeneratedJwtId(); - claims.setIssuedAt(issuedAt); - claims.setSubject(subject); - if (aud.size() == 1) { - claims.setAudience(aud.get(0)); - } else { - claims.setAudience(aud); - } - for (Map.Entry entry : additionalClaims.entrySet()) { - claims.setStringClaim(entry.getKey(), entry.getValue()); - } - RsaJsonWebKey senderJwk = KeyStoreTool.getJsonWebKey(); - JsonWebSignature jws = new JsonWebSignature(); - jws.setPayload(claims.toJson()); - jws.setKeyIdHeaderValue(kid); - jws.setAlgorithmHeaderValue("RS256"); - jws.setKey(senderJwk.getPrivateKey()); - jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256); - - try { - return jws.getCompactSerialization(); - } catch (JoseException e) { - throw new RuntimeException(e); - } - } -} diff --git a/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/TokenLocatorTest.java b/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/TokenLocatorTest.java deleted file mode 100644 index b2110c920..000000000 --- a/felles/sikkerhet/src/test/java/no/nav/vedtak/sikkerhet/jaspic/TokenLocatorTest.java +++ /dev/null @@ -1,54 +0,0 @@ -package no.nav.vedtak.sikkerhet.jaspic; - -import static org.assertj.core.api.Assertions.assertThat; -import static org.mockito.Mockito.when; - -import jakarta.servlet.http.Cookie; -import jakarta.servlet.http.HttpServletRequest; - -import org.junit.jupiter.api.Test; -import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.Mock; -import org.mockito.junit.jupiter.MockitoExtension; - -import no.nav.vedtak.sikkerhet.ContextPathHolder; - -@ExtendWith(MockitoExtension.class) -class TokenLocatorTest { - - @Mock - private HttpServletRequest requestContext; - private TokenLocator tokenLocator = new TokenLocator(); - - - @Test - void skal_finne_token_i_authorization_header() { - ContextPathHolder.instance(); - when(requestContext.getHeader("Authorization")).thenReturn("Bearer eyJhbGciOiJS..."); - assertThat(tokenLocator.getToken(requestContext).get().token()).isEqualTo("eyJhbGciOiJS..."); - } - - @Test - void skal_ikke_finne_token_når_token_ikke_finnes_i_authorization_header() { - ContextPathHolder.instance(); - when(requestContext.getHeader("Authorization")).thenReturn(""); - assertThat(tokenLocator.getToken(requestContext)).isNotPresent(); - - when(requestContext.getHeader("Authorization")).thenReturn(null); - assertThat(tokenLocator.getToken(requestContext)).isNotPresent(); - } - - @Test - void skal_finne_id_token_i_cookie() { - ContextPathHolder.instance("/k9", "/k9"); - when(requestContext.getCookies()).thenReturn(new Cookie[]{new Cookie(TokenLocator.ID_TOKEN_COOKIE_NAME, "eyJhbGciOiJS...")}); - assertThat(tokenLocator.getToken(requestContext).get().token()).isEqualTo("eyJhbGciOiJS..."); - } - - @Test - void skal_ikke_finne_id_token_i_cookie_som_har_feil_navn() { - ContextPathHolder.instance("/k9", "/k9"); - when(requestContext.getCookies()).thenReturn(new Cookie[]{new Cookie("tull", "eyJhbGciOiJS...")}); - assertThat(tokenLocator.getToken(requestContext)).isNotPresent(); - } -} diff --git a/felles/sikkerhet/src/test/resources/logback-test.xml b/felles/sikkerhet/src/test/resources/logback-test.xml deleted file mode 100644 index 375d8576f..000000000 --- a/felles/sikkerhet/src/test/resources/logback-test.xml +++ /dev/null @@ -1,22 +0,0 @@ - - - - - %d [%-5level] [%thread] %logger{5} - [%X{consumerId}, %X{callId}, %X{userId}] - %m%n - - - - - - - - - - - - - - - - - diff --git a/felles/sikkerhet/src/test/resources/test-keystore.jks b/felles/sikkerhet/src/test/resources/test-keystore.jks deleted file mode 100644 index de0cca21a5213aca64ef3fdb89ce7d9589c66e64..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2553 zcmY+EcQo4z8^?oCQ7gnKrLDcnFKGm=J&J3qxLm8!DjFJlR%nn8t95yeP*ki|QA*LO zl!{&}_TH@;z4i*CUhjL}_ug~QbDr~@^Z7o{^XCU3Kz5m#SO5Z~f(@cTG$HPDF`Z$` zCqVMR1PJLAX8;6N>^~w_XE1@);S}4Qwl&+?|6Or%Ffr#7z()W9ybs8;ar_^jJ{JYU z#s_Zhc3?}*BV0ey^|&U5J~XV9GqZqNt-%EF7iUB^mk|5elv;utfdmTggBLO8-%`pH z7l}q+JK{xSX^X;gf1piY^mR0E;|_5f^T{Zu*w)l-_W=N7yY!M>pK;T0)_|%JkamDz zTRWefoN}kNT|MGx>8wO;{%ob*2uv_G=)6t$2Bz=2@(yY~4!0hjwQ~uA6ekJGAHZ5z z@dx$3+C?E3uw2hI3!^-ly)+{1f%C$)45Z|{TeAK#J@Wzt$-$xS;1p3#Jt-`PH(~Sp ze!^Vz&%yDO-VVc5p@Eg{)TS68Z8gaR_zQKLG&?>q_pc!>*3j;g7-K+iST`9ox;N3G zWX8qD$bgq31owc2^kURn5@3{G|4}gup+z3>dC5bxfI4{V24nSLHP)k_ zV$WpO^=SctLq(~}11qfIZna=gW44&}9ht!5;Z z-aP(7)1E8>8noXqgF>jwPA)-%_eF7lCvWvvo>DdIWfW6lkV>FhcRC76T*+beKgkPX*RFgW#(<4de3|+?FQ{s}; z#^gYL0`huRWwx#5&0;9cV>2>zD9g+d_i46ICEVV!?6sydvA|sV+R$g${kKY8wc=5g3oUxzD=VEHEy+4?^ zvDrGM{}S(brl;!Jt)#m}ITkW9W4g5{zJxHTOa(_i)tw~9Ro2zUSyypHK%K^>1m?-0 zN9}WBefdw;fFbcRU%Fn4ejbg6&v`rS|1>ob39BCTmQvJVUk$wXOSSryjyJJ(7vGsS zeCb${wVCgfvCTu}?@%-Jyx03?8su*)=y>=Xux4i-y?%PK4OfFM`@6+N9BPf{YVdu- z#)#)~QL`6OqF?%7IU7U5f}EmfmnQbODH?H81tvo%z8te=dRMao2&+~5L^|1`7Ec&q zfa=F6?Xbkdvf>7gIUNX!rp_-yrx%qATrj4YPvXi`Ge%+^e z#%W8PBPrApn`5Zl;)Zvjp$_jiSeW{T2HPM<980rWukzX(n{gUiYpa%Ae~wgXpY%Ce z|4)6o{Jl_5ukjlhgiwCD@ieG`!w3z7RIpYK%#BA=p9nZ#ie%$R~ZDSx}zf;7y zIx)nAQWsRcTqJqn9=k)li>x;g)3u+x)7eN_oq4BtGXVK1zbg&tU-Zq=cLBG_Z}z+F z;|jJd?#w`|czSf1s^Kbz!(nN;;_WUq35qhP$X#exc7x9Ck_VB|<}m3x`c%m^(+?FU zox$d@&lG*^3`A%QhwzgZdM^H0&D5;tLz^9ONR`XJrJtrUqT^Ho$L!Fhs8D!R2V5Tz z`%9G&7@Sv}8{`i1JFUwgEXV^C4qW;>7J$RRe0JWx9v9)NNTixN90dTXs;EXCylq)wrZmi6C2H zxkSGl7#v@IhsSC_VqR;nVU9C-MBK75L#PD$1*G*`))G+(0Ls8`-bsVSLb&|vhdu4pi;lNnk$(uqap2(wrQs%nnPlD zX#<6Upm2yYt?!TuH%3Ja*C+`wcV%+%cp3|OO!t=>;ewHeFiTS?Ry)dVVkRph7@Ds( zDc`QM(OI>;MSyqwHqDdTDzB^-;ngQ}(NApZO@(hk6zfBy(MZL-Ui4k(d%~!G+3CIn zXOjKX3w7~k@mruY#isqLb$?sm6Bkxh+^o-$I2X<^$IH+3d?2 zDwx#wyFxK>rh+T^>XJOHNzeF^OP)TnaLbgE;Q`<B5BH7PC!&4l z**lHpHaS>OMIouxgH0O z6#;}}vcE8x#lSz&Hg{&LY1G_fEsrNG(ZF&3h_?RuU$E%L<6EW{4et*sQ>yZFNki8& zjxCSwHGC{XuNPIvvSdqVi!Fm(=*32@)gkENrl;7NR5yeL&rb)dYu`Sjv-I;Rk9mL+ z_QG3g*8f`QRCr=>b3z=Th+z{3;w74%(3FHUMgv5yi|I52+Q20M!p5q|&B83g3IfA? zkGNE-yh>llbN;zKlDr}ghJ`;{N2t%)C?yhB_f;D#mOz{=YRoK5#Qc8)eV@76