Issue
I asked a question not long ago to know how to validate jwt token using spring boot and copied the dependencies on the sample href="https://github.com/spring-projects/spring-security-samples/tree/main/servlet/spring-boot/java/oauth2/resource-server/static" rel="nofollow noreferrer">here but updated them for the latest ones.
This is my build.gradle :
import org.apache.tools.ant.filters.ReplaceTokens
plugins {
id 'org.springframework.boot' version '2.4.5'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'org.jetbrains.kotlin.jvm' version '1.4.32'
id 'org.jetbrains.kotlin.plugin.spring' version '1.4.32'
id "org.jetbrains.kotlin.plugin.jpa" version "1.4.32"
}
apply plugin: 'io.spring.dependency-management'
apply plugin: 'kotlin'
apply plugin: 'kotlin-spring'
apply plugin: 'kotlin-jpa'
group = 'com.backend-project'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '1.8'
repositories {
mavenCentral()
}
dependencies {
def appInsightsVersion = '2.6.2'
implementation 'org.springframework.boot:spring-boot-starter-web'
implementation 'org.springframework.boot:spring-boot-starter-websocket'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'com.fasterxml.jackson.module:jackson-module-kotlin'
implementation 'com.microsoft.sqlserver:mssql-jdbc:6.2.1.jre8'
implementation 'com.h2database:h2:1.4.199'
implementation 'io.springfox:springfox-swagger2:2.9.2'
implementation 'io.springfox:springfox-swagger-ui:2.9.2'
implementation 'org.jetbrains.kotlin:kotlin-reflect'
implementation 'org.jetbrains.kotlin:kotlin-stdlib-jdk8'
implementation 'org.hibernate:hibernate-core'
implementation 'javax.xml.bind:jaxb-api'
implementation group: 'com.microsoft.azure', name: 'applicationinsights-web', version: appInsightsVersion
implementation group: 'com.microsoft.azure', name: 'applicationinsights-logging-logback', version: appInsightsVersion
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.springframework.boot:spring-boot-starter-validation:2.4.5'
implementation 'org.springframework.boot:spring-boot-starter-security:2.4.5'
implementation 'org.springframework.boot:spring-boot-starter-oauth2-resource-server:2.4.5'
implementation 'org.springframework.security:spring-security-oauth2-jose:5.3.9.RELEASE'
compile 'org.springframework.security:spring-security-oauth2-core:5.3.9.RELEASE'
compile 'io.jsonwebtoken:jjwt-api:0.11.2'
runtime 'io.jsonwebtoken:jjwt-impl:0.11.2',
'io.jsonwebtoken:jjwt-jackson:0.11.2'
compile 'joda-time:joda-time:2.10.10'
implementation group: 'org.bouncycastle', name: 'bcprov-jdk15on', version: '1.68'
}
compileKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xjsr305=strict']
jvmTarget = '1.8'
}
}
compileTestKotlin {
kotlinOptions {
freeCompilerArgs = ['-Xjsr305=strict']
jvmTarget = '1.8'
}
}
task copyWebConfig(type: Copy) {
from("$rootDir/src/main/templates") {
include 'web.config'
}
into "$buildDir/libs"
filter(ReplaceTokens, tokens: [VERSION: project.version])
inputs.property("VERSION", project.version)
filter(ReplaceTokens, tokens: [PACKAGE_NAME: project.name])
inputs.property("PACKAGE_NAME", project.name)
}
task copyLogBack(type: Copy) {
from("$rootDir") {
include 'logback-spring.xml'
}
into "$buildDir/libs"
}
assemble.dependsOn(copyWebConfig)
assemble.dependsOn(copyLogBack)
this is my web security implementation :
package com.renaulttrucks.transfertprotocolbackend.security.config
import com.renaulttrucks.transfertprotocolbackend.api.config.Router
import org.springframework.beans.factory.annotation.Value
import org.springframework.context.annotation.Bean
import org.springframework.security.config.annotation.web.builders.HttpSecurity
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter
import org.springframework.security.config.http.SessionCreationPolicy
import org.springframework.security.oauth2.jwt.JwtDecoder
import org.springframework.security.oauth2.jwt.NimbusJwtDecoder
import org.springframework.util.ResourceUtils
import java.io.FileInputStream
import java.security.cert.CertificateFactory
import java.security.cert.X509Certificate
import java.security.interfaces.RSAPublicKey
@EnableWebSecurity
class SecurityConfig : WebSecurityConfigurerAdapter() {
@Value("\${security.enabled}")
val securityEnabled : Boolean? = false
@Value("\${jwt.key-path}")
var keyPath: String? = null
var publicKey: RSAPublicKey? = null
override fun configure(http: HttpSecurity) {
if(!securityEnabled!!) {
http.httpBasic()
.and()
.authorizeRequests()
.antMatchers("/**").permitAll()
.and()
.csrf().disable()
.formLogin().disable()
} else {
http
.authorizeRequests()
.antMatchers("/api/companies/**").permitAll()
.antMatchers(Router.API_PATH + "/**").authenticated()
.and()
.httpBasic()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.anonymous()
.and()
.securityContext()
.and()
.headers().disable()
.rememberMe().disable()
.requestCache().disable()
.csrf().disable()
.x509().disable()
.httpBasic().disable()
.formLogin().disable()
.logout().disable()
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.decoder(jwtDecoder()))
)
}
}
@Bean
fun jwtDecoder(): JwtDecoder? {
return NimbusJwtDecoder.withPublicKey(getPublicKeyFromString()).build()
}
fun getPublicKeyFromString(): RSAPublicKey? {
if (this.publicKey != null) {
return this.publicKey
}
val fin = FileInputStream(ResourceUtils.getFile(keyPath!!))
val f: CertificateFactory = CertificateFactory.getInstance("X.509")
val certificate: X509Certificate = f.generateCertificate(fin) as X509Certificate
publicKey = certificate.getPublicKey() as RSAPublicKey?
return publicKey
}
}
It gives me the following errors which I don't understand why I'm getting since I'm following the documentation :
Even when trying the kotlin dsl version like here by changing my configure function like bellow :
override fun configure(http: HttpSecurity) {
http {
authorizeRequests {
authorize(anyRequest, authenticated)
}
oauth2ResourceServer {
jwt {
jwtDecoder = jwtDecoder()
}
}
}
}
it gives me the following errors :
The first line's this :
: Unresolved reference. None of the following candidates is applicable because of receiver type mismatch: public operator fun <T, R> DeepRecursiveFunction<TypeVariable(T), TypeVariable(R)>.invoke(value: TypeVariable(T)): TypeVariable(R) defined in kotlin
Running gradlew dependencyInsight --dependency org.springframework.security:spring-security-config - -configuration runtimeClasspath
gives me this :
Welcome to Gradle 7.0!
Here are the highlights of this release:
- File system watching enabled by default
- Support for running with and building Java 16 projects
- Native support for Apple Silicon processors
- Dependency catalog feature preview
For more details see https://docs.gradle.org/7.0/release-notes.html
Starting a Gradle Daemon, 1 busy and 2 incompatible Daemons could not be reused, use --status for details
> Evaluating settings
> Task :dependencyInsight
org.springframework.security:spring-security-config:5.4.6 (selected by rule)
variant "runtime" [
org.gradle.status = release (not requested)
org.gradle.usage = java-runtime
org.gradle.libraryelements = jar
org.gradle.category = library
Requested attributes not found in the selected variant:
org.gradle.dependency.bundling = external
org.gradle.jvm.environment = standard-jvm
org.jetbrains.kotlin.platform.type = jvm
org.gradle.jvm.version = 8
]
org.springframework.security:spring-security-config:5.4.6
+--- org.springframework.boot:spring-boot-starter-oauth2-resource-server:2.4.5
| \--- runtimeClasspath
\--- org.springframework.boot:spring-boot-starter-security:2.4.5
\--- runtimeClasspath
(*) - dependencies omitted (listed previously)
A web-based, searchable dependency report is available by adding the --scan option.
BUILD SUCCESSFUL in 21s
1 actionable task: 1 executed
Solution
Using the lambda version solved the issue as user Eleftheria Stein-Kousathana suggested :
oauth2ResourceServer().jwt().decoder(jwtDecoder())
Answered By - Hadestructhor
Answer Checked By - Pedro (JavaFixing Volunteer)