From 052dee9dce2b89cda3b663a2cbb277919f2567c8 Mon Sep 17 00:00:00 2001 From: simhos <104764765+simhos@users.noreply.github.com> Date: Fri, 20 Oct 2023 08:59:15 +0200 Subject: [PATCH] Legger til tester av maskinporten token cache og token generator (#254) --- .../maskinporten/MaskinportenTestUtils.kt | 21 ++++++ .../MaskinportenTokenCacheTest.kt | 30 ++++++++ .../MaskinportenTokenGeneratorTest.kt | 75 +++++++++++++++++++ 3 files changed, 126 insertions(+) create mode 100644 src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTestUtils.kt create mode 100644 src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTokenCacheTest.kt create mode 100644 src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTokenGeneratorTest.kt diff --git a/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTestUtils.kt b/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTestUtils.kt new file mode 100644 index 0000000..8f7dba4 --- /dev/null +++ b/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTestUtils.kt @@ -0,0 +1,21 @@ +package no.nav.bidrag.commons.security.maskinporten + +import com.nimbusds.jose.JWSAlgorithm +import com.nimbusds.jose.JWSHeader +import com.nimbusds.jose.crypto.RSASSASigner +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator +import com.nimbusds.jwt.JWTClaimsSet +import com.nimbusds.jwt.SignedJWT +import java.util.Date + +object MaskinportenTestUtils { + + fun opprettMaskinportenToken(utgarOm: Int): String { + val privateKey = RSAKeyGenerator(2048).keyID("123").generate() + + val jwtClaimsSet = JWTClaimsSet.Builder().expirationTime(Date(Date().time + (utgarOm * 1000))).build() + val signedJwt = SignedJWT(JWSHeader.Builder(JWSAlgorithm.RS256).keyID(privateKey.keyID).build(), jwtClaimsSet) + signedJwt.sign(RSASSASigner(privateKey)) + return signedJwt.serialize() + } +} diff --git a/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTokenCacheTest.kt b/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTokenCacheTest.kt new file mode 100644 index 0000000..68070e0 --- /dev/null +++ b/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTokenCacheTest.kt @@ -0,0 +1,30 @@ +package no.nav.bidrag.commons.security.maskinporten + +import io.kotest.matchers.shouldBe +import io.kotest.matchers.shouldNotBe +import no.nav.bidrag.commons.security.maskinporten.MaskinportenTestUtils.opprettMaskinportenToken +import org.junit.jupiter.api.Test + +internal class MaskinportenTokenCacheTest { + + @Test + fun `skal ikke returnere token om token utgår om under 20 sekunder`() { + val tokenCache = MaskinportenTokenCache(opprettMaskinportenToken(19)) + tokenCache.maskinportenToken shouldBe null + } + + @Test + fun `skal returnere token om token har lenger gjennværende levetid enn 20 sekunder`() { + val tokenCache = MaskinportenTokenCache(opprettMaskinportenToken(23)) + tokenCache.maskinportenToken shouldNotBe null + } + + @Test + fun `skal ved renew opprette nytt token i cache`() { + val tokenCache = MaskinportenTokenCache(opprettMaskinportenToken(-10)) + tokenCache.maskinportenToken shouldBe null + + tokenCache.renew(opprettMaskinportenToken(120)) + tokenCache.maskinportenToken shouldNotBe null + } +} diff --git a/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTokenGeneratorTest.kt b/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTokenGeneratorTest.kt new file mode 100644 index 0000000..9f5153d --- /dev/null +++ b/src/test/kotlin/no/nav/bidrag/commons/security/maskinporten/MaskinportenTokenGeneratorTest.kt @@ -0,0 +1,75 @@ +package no.nav.bidrag.commons.security.maskinporten + +import com.nimbusds.jose.JWSAlgorithm +import com.nimbusds.jose.JWSVerifier +import com.nimbusds.jose.crypto.RSASSAVerifier +import com.nimbusds.jose.jwk.RSAKey +import com.nimbusds.jose.jwk.gen.RSAKeyGenerator +import com.nimbusds.jwt.SignedJWT +import io.kotest.matchers.shouldBe +import org.junit.jupiter.api.Test +import java.util.Date +import kotlin.math.absoluteValue + +class MaskinportenTokenGeneratorTest { + private val scope = "skatt:testscope.read" + private val PORT = 8096 + private val TOKEN_PATH = "/token" + private val MASKINPORTEN_MOCK_HOST = "http://localhost:$PORT" + + + val maskinportenConfig = MaskinportenConfig( + tokenUrl = MASKINPORTEN_MOCK_HOST + TOKEN_PATH, + audience = MASKINPORTEN_MOCK_HOST, + clientId = "17b3e4e8-8203-4463-a947-5c24021b7742", + privateKey = RSAKeyGenerator(2048).keyID("123").generate().toString(), + validInSeconds = 120, + scope = "skatt:testscope.read skatt:testscope.write") + + + @Test + fun `Skal sjekke at maskonporten token er signed med privat key i config`() { + val config = maskinportenConfig + val generator = MaskinportenTokenGenerator(config) + val signedJWT = SignedJWT.parse(generator.genererJwtToken(scope)) + val verifier: JWSVerifier = RSASSAVerifier(RSAKey.parse(config.privateKey).toRSAPublicKey()) + + signedJWT.verify(verifier) shouldBe true + } + + @Test + fun `Skal sjekke at benyttet algorytme i header er rsa256`() { + val config = maskinportenConfig + val generator = MaskinportenTokenGenerator(config) + val signedJWT = SignedJWT.parse(generator.genererJwtToken(scope)) + + (signedJWT.header.algorithm as JWSAlgorithm).name shouldBe "RS256" + } + + @Test + fun `Skal sjekke at scope claims er lagt til i token body`() { + val config = maskinportenConfig + val generator = MaskinportenTokenGenerator(config) + val signedJWT = SignedJWT.parse(generator.genererJwtToken(scope)) + + signedJWT.jwtClaimsSet.audience[0] shouldBe config.audience + signedJWT.jwtClaimsSet.issuer shouldBe config.clientId + signedJWT.jwtClaimsSet.getStringClaim("scope") shouldBe scope + } + + @Test + fun `Skal sjekke at timestamps blir satt riktig på token body`() { + val config = maskinportenConfig + val generator = MaskinportenTokenGenerator(config) + val signedJWT = SignedJWT.parse(generator.genererJwtToken(scope)) + + val issuedAt = signedJWT.jwtClaimsSet.issueTime + val expirationTime = signedJWT.jwtClaimsSet.expirationTime + + Date() likInnenEtSekund issuedAt shouldBe true + Date() plusSekunder config.validInSeconds likInnenEtSekund expirationTime shouldBe true + } + + private infix fun Date.likInnenEtSekund(date: Date): Boolean = (time - date.time).absoluteValue < 1000L + private infix fun Date.plusSekunder(seconds: Int): Date = Date(time + seconds * 1000) +} \ No newline at end of file