Skip to content

Commit

Permalink
Merge pull request #809 from navikt/kotlin-filter
Browse files Browse the repository at this point in the history
convert filters to kotlin
  • Loading branch information
jan-olaveide authored Dec 3, 2023
2 parents a697298 + 282c943 commit f15188d
Show file tree
Hide file tree
Showing 14 changed files with 564 additions and 554 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package no.nav.security.token.support.core.context;


public interface TokenValidationContextHolder {

TokenValidationContext getTokenValidationContext();

void setTokenValidationContext(TokenValidationContext tokenValidationContext);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ protected boolean handleProtectedWithClaimsAnnotation(ProtectedWithClaims a, Jwt
}

protected boolean handleProtectedWithClaims(String issuer, String[] requiredClaims, boolean combineWithOr, JwtToken jwtToken) {
if (Objects.nonNull(issuer) && issuer.length() > 0) {
if (Objects.nonNull(issuer) && !issuer.isEmpty()) {
return containsRequiredClaims(jwtToken, combineWithOr, requiredClaims);
}
return true;
Expand Down
12 changes: 9 additions & 3 deletions token-validation-filter/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,18 @@
<artifactId>logback-classic</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
</dependency>
</dependencies>
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<artifactId>kotlin-maven-plugin</artifactId>
<groupId>org.jetbrains.kotlin</groupId>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
Expand Down

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package no.nav.security.token.support.filter

import jakarta.servlet.Filter
import jakarta.servlet.FilterChain
import jakarta.servlet.FilterConfig
import jakarta.servlet.ServletException
import jakarta.servlet.ServletRequest
import jakarta.servlet.ServletResponse
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import java.io.IOException
import java.time.LocalDateTime
import java.time.ZoneId
import java.time.temporal.ChronoUnit.MINUTES
import java.util.Date
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import no.nav.security.token.support.core.JwtTokenConstants
import no.nav.security.token.support.core.context.TokenValidationContextHolder
import no.nav.security.token.support.core.jwt.JwtTokenClaims

/**
* Checks the expiry time in a validated token against a preconfigured threshold
* and returns a custom http header if this threshold is reached.
*
*
* Can be used to check if the token is about to expire and inform the caller
*/
class JwtTokenExpiryFilter(private val contextHolder : TokenValidationContextHolder, private val expiryThresholdInMinutes : Long) : Filter {

override fun doFilter(request : ServletRequest, response : ServletResponse, chain : FilterChain) {
if (request is HttpServletRequest) {
addHeaderOnTokenExpiryThreshold(response as HttpServletResponse)
chain.doFilter(request, response)
}
else {
chain.doFilter(request, response)
}
}

override fun destroy() {}

override fun init(filterConfig : FilterConfig) {}

private fun addHeaderOnTokenExpiryThreshold(response : HttpServletResponse) {
val tokenValidationContext = contextHolder.tokenValidationContext
LOG.debug("Getting TokenValidationContext: {}", tokenValidationContext)
if (tokenValidationContext != null) {
LOG.debug("Getting issuers from validationcontext {}", tokenValidationContext.issuers)
for (issuer in tokenValidationContext.issuers) {
val jwtTokenClaims = tokenValidationContext.getClaims(issuer)
if (tokenExpiresBeforeThreshold(jwtTokenClaims)) {
LOG.debug("Setting response header {}", JwtTokenConstants.TOKEN_EXPIRES_SOON_HEADER)
response.setHeader(JwtTokenConstants.TOKEN_EXPIRES_SOON_HEADER, "true")
}
else {
LOG.debug("Token is still within expiry threshold.")
}
}
}
}

private fun tokenExpiresBeforeThreshold(jwtTokenClaims : JwtTokenClaims) : Boolean {
val expiryDate = jwtTokenClaims["exp"] as Date
val expiry = LocalDateTime.ofInstant(expiryDate.toInstant(), ZoneId.systemDefault())
val minutesUntilExpiry = LocalDateTime.now().until(expiry, MINUTES)
LOG.debug("Checking token at time {} with expirationTime {} for how many minutes until expiry: {}",
LocalDateTime.now(), expiry, minutesUntilExpiry)
if (minutesUntilExpiry <= expiryThresholdInMinutes) {
LOG.debug("There are {} minutes until expiry which is equal to or less than the configured threshold {}",
minutesUntilExpiry, expiryThresholdInMinutes)
return true
}
return false
}

override fun toString() = ("${javaClass.getSimpleName()} [contextHolder=$contextHolder, expiryThresholdInMinutes=$expiryThresholdInMinutes]")

companion object {

private val LOG : Logger = LoggerFactory.getLogger(JwtTokenExpiryFilter::class.java)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
package no.nav.security.token.support.filter

import jakarta.servlet.Filter
import jakarta.servlet.FilterChain
import jakarta.servlet.FilterConfig
import jakarta.servlet.ServletRequest
import jakarta.servlet.ServletResponse
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import no.nav.security.token.support.core.context.TokenValidationContextHolder
import no.nav.security.token.support.core.http.HttpRequest
import no.nav.security.token.support.core.http.HttpRequest.NameValue
import no.nav.security.token.support.core.validation.JwtTokenValidationHandler

open class JwtTokenValidationFilter(private val jwtTokenValidationHandler : JwtTokenValidationHandler, private val contextHolder : TokenValidationContextHolder) : Filter {

override fun destroy() {}

override fun doFilter(request : ServletRequest, response : ServletResponse, chain : FilterChain) {
if (request is HttpServletRequest) {
doTokenValidation(request, response as HttpServletResponse, chain)
}
else {
chain.doFilter(request, response)
}
}

override fun init(filterConfig : FilterConfig) {}

private fun doTokenValidation(request : HttpServletRequest, response : HttpServletResponse, chain : FilterChain) {
contextHolder.tokenValidationContext = jwtTokenValidationHandler.getValidatedTokens(fromHttpServletRequest(request))
try {
chain.doFilter(request, response)
}
finally {
contextHolder.tokenValidationContext = null
}
}

companion object {

@JvmStatic
fun fromHttpServletRequest(request: HttpServletRequest) = object : HttpRequest {
override fun getHeader(headerName: String) = request.getHeader(headerName)
override fun getCookies() = request.cookies?.map {
object : NameValue {
override fun getName() = it.name
override fun getValue() = it.value
}
}?.toTypedArray()
}
}
}
Loading

0 comments on commit f15188d

Please sign in to comment.