From 59ce38a456687303f1c94ef80c542f0d23b18a80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20=C3=81lvarez=20=C3=81lvarez?= Date: Sun, 29 Sep 2024 18:31:53 +0200 Subject: [PATCH] Add support for user tracking in spring security (#7633) --- .../appsec/user/AppSecEventTrackerImpl.java | 9 + .../AppSecEventTrackerSpecification.groovy | 19 + .../spring-security-5/build.gradle | 40 +- .../spring-security-5/gradle.lockfile | 403 ++++++++++-------- .../AppSecDeferredContext.java | 22 + ...AuthenticationProviderInstrumentation.java | 19 +- .../SecurityContextHolderInstrumentation.java | 90 ++++ .../SpringSecurityUserEventDecorator.java | 19 + .../UserDetailsManagerInstrumentation.java | 17 +- ...rnameNotFoundExceptionInstrumentation.java | 11 +- .../AuthenticationProviderAdvice.java | 19 - .../UserDetailsManagerAdvice.java | 17 - .../UsernameNotFoundExceptionAdvice.java | 11 - .../springsecurity5/SecurityConfig.groovy | 33 +- .../SpringBootBasedTest.groovy | 40 +- .../springsecurity5/TestEndpoint.groovy | 1 + .../custom/CustomAuthenticationFilter.java | 6 +- .../src/test/resources/schema.sql | 30 -- .../spring-security-6/build.gradle | 32 ++ .../spring-security-6/gradle.lockfile | 272 ++++++++++++ .../springsecurity6/AppConfig.groovy | 11 + .../springsecurity6/SecurityConfig.groovy | 58 +++ .../SpringBootBasedTest.groovy | 291 +++++++++++++ .../springsecurity6/TestEndpoint.groovy | 50 +++ .../springsecurity6/UserController.groovy | 45 ++ .../custom/CustomAuthenticationFilter.java | 33 ++ .../custom/CustomAuthenticationProvider.java | 18 + .../custom/CustomAuthenticationToken.java | 24 ++ .../trace/api/appsec/AppSecEventTracker.java | 2 + settings.gradle | 1 + 30 files changed, 1326 insertions(+), 317 deletions(-) create mode 100644 dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/AppSecDeferredContext.java create mode 100644 dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/SecurityContextHolderInstrumentation.java rename dd-java-agent/instrumentation/spring-security-5/src/main/{java17 => java}/datadog/trace/instrumentation/springsecurity5/SpringSecurityUserEventDecorator.java (91%) delete mode 100644 dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/AuthenticationProviderAdvice.java delete mode 100644 dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/UserDetailsManagerAdvice.java delete mode 100644 dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/UsernameNotFoundExceptionAdvice.java delete mode 100644 dd-java-agent/instrumentation/spring-security-5/src/test/resources/schema.sql create mode 100644 dd-java-agent/instrumentation/spring-security-6/build.gradle create mode 100644 dd-java-agent/instrumentation/spring-security-6/gradle.lockfile create mode 100644 dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/AppConfig.groovy create mode 100644 dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/SecurityConfig.groovy create mode 100644 dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/SpringBootBasedTest.groovy create mode 100644 dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/TestEndpoint.groovy create mode 100644 dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/UserController.groovy create mode 100644 dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationFilter.java create mode 100644 dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationProvider.java create mode 100644 dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationToken.java diff --git a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/user/AppSecEventTrackerImpl.java b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/user/AppSecEventTrackerImpl.java index 039312c7c93..e7cf336fa11 100644 --- a/dd-java-agent/appsec/src/main/java/com/datadog/appsec/user/AppSecEventTrackerImpl.java +++ b/dd-java-agent/appsec/src/main/java/com/datadog/appsec/user/AppSecEventTrackerImpl.java @@ -96,6 +96,15 @@ public void onLoginFailureEvent( } } + @Override + public void onUserEvent(UserIdCollectionMode mode, String userId) { + TraceSegment segment = beforeEvent(mode, userId); + if (segment == null) { + return; + } + onUserId(mode, segment, userId, EVENTS.userId()); + } + @Override public void onCustomEvent( final UserIdCollectionMode mode, final String eventName, final Map metadata) { diff --git a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/user/AppSecEventTrackerSpecification.groovy b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/user/AppSecEventTrackerSpecification.groovy index 8ec0447c9e6..f38200fff1b 100644 --- a/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/user/AppSecEventTrackerSpecification.groovy +++ b/dd-java-agent/appsec/src/test/groovy/com/datadog/appsec/user/AppSecEventTrackerSpecification.groovy @@ -237,6 +237,25 @@ class AppSecEventTrackerSpecification extends DDSpecification { 'ident' | 'identification' | 'user doesn\'t exist' | USER_ID } + def "test onUserEvent (#mode)"() { + setup: + final collectionMode = UserIdCollectionMode.fromString(mode, null) + + when: + tracker.onUserEvent(collectionMode, USER_ID) + + then: + 1 * traceSegment.getTagTop('_dd.appsec.user.collection_mode') >> null + 1 * userCallback.apply(_ as RequestContext, collectionMode, expectedUserId) >> NoopFlow.INSTANCE + 0 * _ + + where: + mode | modeTag | expectedUserId + 'anon' | 'anonymization' | ANONYMIZED_USER_ID + 'ident' | 'identification' | USER_ID + } + + def "test onUserNotFound (#mode)"() { setup: final collectionMode = UserIdCollectionMode.fromString(mode, null) diff --git a/dd-java-agent/instrumentation/spring-security-5/build.gradle b/dd-java-agent/instrumentation/spring-security-5/build.gradle index dd425272adc..51bc36007cf 100644 --- a/dd-java-agent/instrumentation/spring-security-5/build.gradle +++ b/dd-java-agent/instrumentation/spring-security-5/build.gradle @@ -3,39 +3,27 @@ muzzle { group = 'org.springframework.security' module = 'spring-security-core' versions = "[5.5.0,)" - // assertInverse = true } } -ext { - minJavaVersionForTests = JavaVersion.VERSION_17 -} - apply from: "$rootDir/gradle/java.gradle" +addTestSuiteForDir('latestDepTest', 'test') -[compileMain_java17Java, compileTestJava].each { - it.configure { - setJavaVersion(it, 17) - sourceCompatibility = JavaVersion.VERSION_1_8 - targetCompatibility = JavaVersion.VERSION_1_8 - } -} - -compileTestGroovy { - javaLauncher = getJavaLauncherFor(17) -} +final springSecurityVersion = '5.8.2' +final springBootVersion = '2.6.0' dependencies { - main_java17CompileOnly group: 'org.springframework.security', name: 'spring-security-core', version: '5.5.0' - compileOnly group: 'org.springframework.security', name: 'spring-security-core', version: '5.5.0' - - testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '3.0.0' - testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '3.0.0' - testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '3.0.0' - testImplementation 'org.springframework.boot:spring-boot-starter-jdbc:3.0.0' + compileOnly group: 'org.springframework.security', name: 'spring-security-core', version: springSecurityVersion testImplementation testFixtures(project(':dd-java-agent:appsec')) - testImplementation project(':dd-java-agent:instrumentation:tomcat-appsec-6') - testImplementation project(':dd-java-agent:instrumentation:tomcat-5.5') - testImplementation 'com.h2database:h2:2.1.212' + testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: springBootVersion + testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion + testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: springBootVersion + + latestDepTestImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '2.+' + latestDepTestImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '2.+' + latestDepTestImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '2.+' + + testRuntimeOnly project(':dd-java-agent:instrumentation:tomcat-appsec-6') + testRuntimeOnly project(':dd-java-agent:instrumentation:tomcat-5.5') } diff --git a/dd-java-agent/instrumentation/spring-security-5/gradle.lockfile b/dd-java-agent/instrumentation/spring-security-5/gradle.lockfile index 8dd9809b3b3..c4422c4872b 100644 --- a/dd-java-agent/instrumentation/spring-security-5/gradle.lockfile +++ b/dd-java-agent/instrumentation/spring-security-5/gradle.lockfile @@ -1,219 +1,258 @@ # This is a Gradle generated file for dependency locking. # Manual edits can break the build and are not advised. # This file is expected to be part of source control. -cafe.cryptography:curve25519-elisabeth:0.1.0=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -cafe.cryptography:ed25519-elisabeth:0.1.0=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -ch.qos.logback:logback-classic:1.4.5=testCompileClasspath,testRuntimeClasspath -ch.qos.logback:logback-core:1.4.5=testCompileClasspath,testRuntimeClasspath -com.beust:jcommander:1.78=testRuntimeClasspath -com.blogspot.mydailyjava:weak-lock-free:0.17=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq.okhttp3:okhttp:3.12.15=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq.okio:okio:1.17.6=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:dd-javac-plugin-client:0.1.7=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.datadoghq:java-dogstatsd-client:4.4.0=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.datadoghq:sketches-java:0.8.3=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.fasterxml.jackson.core:jackson-annotations:2.14.1=testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson.core:jackson-core:2.14.1=testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson.core:jackson-databind:2.14.1=testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.1=testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.1=testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson.module:jackson-module-parameter-names:2.14.1=testCompileClasspath,testRuntimeClasspath -com.fasterxml.jackson:jackson-bom:2.14.1=testCompileClasspath,testRuntimeClasspath -com.github.javaparser:javaparser-core:3.25.1=testCompileClasspath,testRuntimeClasspath -com.github.jnr:jffi:1.3.13=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-a64asm:1.0.0=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-constants:0.10.4=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-enxio:0.32.17=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-ffi:2.2.16=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-posix:3.1.19=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-unixsocket:0.38.22=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.jnr:jnr-x86asm:1.0.2=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.github.spotbugs:spotbugs-annotations:4.2.0=compileClasspath,testCompileClasspath,testRuntimeClasspath +cafe.cryptography:curve25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +cafe.cryptography:ed25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +ch.qos.logback:logback-classic:1.2.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +ch.qos.logback:logback-classic:1.2.7=testCompileClasspath,testRuntimeClasspath +ch.qos.logback:logback-core:1.2.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +ch.qos.logback:logback-core:1.2.7=testCompileClasspath,testRuntimeClasspath +com.beust:jcommander:1.78=latestDepTestRuntimeClasspath,testRuntimeClasspath +com.blogspot.mydailyjava:weak-lock-free:0.17=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okhttp3:okhttp:3.12.15=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okio:okio:1.17.6=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:dd-javac-plugin-client:0.1.7=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:java-dogstatsd-client:4.4.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.datadoghq:sketches-java:0.8.3=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-annotations:2.13.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-annotations:2.13.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.core:jackson-core:2.13.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-core:2.13.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.core:jackson-databind:2.13.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-databind:2.13.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.13.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.13.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.0=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.module:jackson-module-parameter-names:2.13.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson:jackson-bom:2.13.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.github.javaparser:javaparser-core:3.25.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.github.jnr:jffi:1.3.13=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-a64asm:1.0.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-constants:0.10.4=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-enxio:0.32.17=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-ffi:2.2.16=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-posix:3.1.19=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-unixsocket:0.38.22=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-x86asm:1.0.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.2.0=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath com.github.spotbugs:spotbugs-annotations:4.7.3=spotbugs com.github.spotbugs:spotbugs:4.7.3=spotbugs -com.github.stefanbirkner:system-rules:1.19.0=testCompileClasspath,testRuntimeClasspath -com.google.auto.service:auto-service-annotations:1.0-rc7=annotationProcessor,compileClasspath,testAnnotationProcessor,testCompileClasspath -com.google.auto.service:auto-service:1.0-rc7=annotationProcessor,testAnnotationProcessor -com.google.auto:auto-common:0.10=annotationProcessor,testAnnotationProcessor -com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath +com.github.stefanbirkner:system-rules:1.19.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.auto.service:auto-service-annotations:1.0-rc7=annotationProcessor,compileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,testAnnotationProcessor,testCompileClasspath +com.google.auto.service:auto-service:1.0-rc7=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.auto:auto-common:0.10=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath com.google.code.gson:gson:2.9.1=spotbugs -com.google.errorprone:error_prone_annotations:2.2.0=annotationProcessor,testAnnotationProcessor -com.google.guava:failureaccess:1.0.1=annotationProcessor,testAnnotationProcessor -com.google.guava:guava:20.0=testCompileClasspath,testRuntimeClasspath -com.google.guava:guava:27.0.1-jre=annotationProcessor,testAnnotationProcessor -com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,testAnnotationProcessor -com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,testAnnotationProcessor -com.google.re2j:re2j:1.7=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -com.h2database:h2:2.1.212=testCompileClasspath,testRuntimeClasspath -com.jayway.jsonpath:json-path:2.7.0=testCompileClasspath,testRuntimeClasspath -com.squareup.moshi:moshi:1.11.0=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.squareup.okhttp3:logging-interceptor:3.12.12=testCompileClasspath,testRuntimeClasspath -com.squareup.okhttp3:okhttp:3.12.12=testCompileClasspath,testRuntimeClasspath -com.squareup.okio:okio:1.17.5=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -com.thoughtworks.qdox:qdox:1.12.1=testRuntimeClasspath -com.vaadin.external.google:android-json:0.0.20131108.vaadin1=testCompileClasspath,testRuntimeClasspath -com.zaxxer:HikariCP:5.0.1=testCompileClasspath,testRuntimeClasspath +com.google.errorprone:error_prone_annotations:2.2.0=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:failureaccess:1.0.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:guava:20.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.guava:guava:27.0.1-jre=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.re2j:re2j:1.7=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.jayway.jsonpath:json-path:2.6.0=testCompileClasspath,testRuntimeClasspath +com.jayway.jsonpath:json-path:2.7.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.squareup.moshi:moshi:1.11.0=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:logging-interceptor:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:okhttp:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okio:okio:1.17.5=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.thoughtworks.qdox:qdox:1.12.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +com.vaadin.external.google:android-json:0.0.20131108.vaadin1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath commons-codec:commons-codec:1.15=spotbugs -commons-fileupload:commons-fileupload:1.5=testCompileClasspath,testRuntimeClasspath -commons-io:commons-io:2.11.0=testCompileClasspath,testRuntimeClasspath +commons-fileupload:commons-fileupload:1.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +commons-io:commons-io:2.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath de.thetaphi:forbiddenapis:3.1=compileClasspath -info.picocli:picocli:4.6.3=testRuntimeClasspath -io.micrometer:micrometer-commons:1.10.1=testCompileClasspath,testRuntimeClasspath -io.micrometer:micrometer-observation:1.10.1=testCompileClasspath,testRuntimeClasspath -io.sqreen:libsqreen:11.0.1=testRuntimeClasspath -jakarta.activation:jakarta.activation-api:2.1.0=testCompileClasspath,testRuntimeClasspath -jakarta.annotation:jakarta.annotation-api:2.1.1=testCompileClasspath,testRuntimeClasspath -jakarta.xml.bind:jakarta.xml.bind-api:4.0.0=testCompileClasspath,testRuntimeClasspath -javax.servlet:javax.servlet-api:3.1.0=testCompileClasspath,testRuntimeClasspath +info.picocli:picocli:4.6.3=latestDepTestRuntimeClasspath,testRuntimeClasspath +io.sqreen:libsqreen:11.0.0=latestDepTestRuntimeClasspath,testRuntimeClasspath +jakarta.activation:jakarta.activation-api:1.2.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +jakarta.annotation:jakarta.annotation-api:1.3.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +jakarta.xml.bind:jakarta.xml.bind-api:2.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +javax.servlet:javax.servlet-api:3.1.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath jaxen:jaxen:1.2.0=spotbugs -jline:jline:2.14.6=testRuntimeClasspath -junit:junit-dep:4.11=testCompileClasspath,testRuntimeClasspath -junit:junit:4.13.2=testCompileClasspath,testRuntimeClasspath -net.bytebuddy:byte-buddy-agent:1.14.18=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -net.bytebuddy:byte-buddy:1.14.18=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath -net.java.dev.jna:jna-platform:5.8.0=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -net.java.dev.jna:jna:5.8.0=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -net.jcip:jcip-annotations:1.0=compileClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath -net.minidev:accessors-smart:2.4.7=testCompileClasspath,testRuntimeClasspath -net.minidev:json-smart:2.4.7=testCompileClasspath,testRuntimeClasspath +jline:jline:2.14.6=latestDepTestRuntimeClasspath,testRuntimeClasspath +junit:junit-dep:4.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +junit:junit:4.13.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.14.18=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy:1.14.18=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.java.dev.jna:jna-platform:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.java.dev.jna:jna:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.jcip:jcip-annotations:1.0=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath +net.minidev:accessors-smart:2.4.7=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +net.minidev:json-smart:2.4.7=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath net.sf.saxon:Saxon-HE:11.4=spotbugs -org.apache.ant:ant-antlr:1.10.12=testRuntimeClasspath +org.apache.ant:ant-antlr:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath org.apache.ant:ant-antlr:1.9.15=codenarc -org.apache.ant:ant-junit:1.10.12=testRuntimeClasspath +org.apache.ant:ant-junit:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath org.apache.ant:ant-junit:1.9.15=codenarc -org.apache.ant:ant-launcher:1.10.12=testRuntimeClasspath -org.apache.ant:ant:1.10.12=testCompileClasspath,testRuntimeClasspath +org.apache.ant:ant-launcher:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant:1.10.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.apache.bcel:bcel:6.5.0=spotbugs org.apache.commons:commons-lang3:3.12.0=spotbugs org.apache.commons:commons-text:1.10.0=spotbugs org.apache.httpcomponents.client5:httpclient5:5.1.3=spotbugs org.apache.httpcomponents.core5:httpcore5-h2:5.1.3=spotbugs org.apache.httpcomponents.core5:httpcore5:5.1.3=spotbugs -org.apache.logging.log4j:log4j-api:2.19.0=spotbugs,testCompileClasspath,testRuntimeClasspath +org.apache.logging.log4j:log4j-api:2.14.1=testCompileClasspath,testRuntimeClasspath +org.apache.logging.log4j:log4j-api:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.logging.log4j:log4j-api:2.19.0=spotbugs org.apache.logging.log4j:log4j-core:2.19.0=spotbugs -org.apache.logging.log4j:log4j-to-slf4j:2.19.0=testCompileClasspath,testRuntimeClasspath -org.apache.tomcat.embed:tomcat-embed-core:10.1.1=testCompileClasspath,testRuntimeClasspath -org.apache.tomcat.embed:tomcat-embed-el:10.1.1=testCompileClasspath,testRuntimeClasspath -org.apache.tomcat.embed:tomcat-embed-websocket:10.1.1=testCompileClasspath,testRuntimeClasspath -org.apiguardian:apiguardian-api:1.1.2=testCompileClasspath -org.assertj:assertj-core:3.23.1=testCompileClasspath,testRuntimeClasspath -org.checkerframework:checker-qual:2.5.2=annotationProcessor,testAnnotationProcessor -org.codehaus.groovy:groovy-all:3.0.17=testCompileClasspath,testRuntimeClasspath +org.apache.logging.log4j:log4j-to-slf4j:2.14.1=testCompileClasspath,testRuntimeClasspath +org.apache.logging.log4j:log4j-to-slf4j:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-core:9.0.55=testCompileClasspath,testRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-core:9.0.83=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-el:9.0.55=testCompileClasspath,testRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-el:9.0.83=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-websocket:9.0.55=testCompileClasspath,testRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-websocket:9.0.83=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apiguardian:apiguardian-api:1.1.2=latestDepTestCompileClasspath,testCompileClasspath +org.assertj:assertj-core:3.21.0=testCompileClasspath,testRuntimeClasspath +org.assertj:assertj-core:3.22.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.checkerframework:checker-qual:2.5.2=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +org.codehaus.groovy:groovy-all:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.codehaus.groovy:groovy-ant:2.5.14=codenarc -org.codehaus.groovy:groovy-ant:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-astbuilder:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-cli-picocli:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-console:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-datetime:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-docgenerator:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-ant:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-astbuilder:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-cli-picocli:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-console:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-datetime:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-docgenerator:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.codehaus.groovy:groovy-groovydoc:2.5.14=codenarc -org.codehaus.groovy:groovy-groovydoc:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-groovysh:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-jmx:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovydoc:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovysh:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jmx:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.codehaus.groovy:groovy-json:2.5.14=codenarc -org.codehaus.groovy:groovy-json:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-jsr223:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-macro:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-nio:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-servlet:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-sql:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-swing:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-json:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jsr223:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-macro:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-nio:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-servlet:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-sql:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-swing:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.codehaus.groovy:groovy-templates:2.5.14=codenarc -org.codehaus.groovy:groovy-templates:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-test-junit5:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-test:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.groovy:groovy-testng:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-templates:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test-junit5:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-testng:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.codehaus.groovy:groovy-xml:2.5.14=codenarc -org.codehaus.groovy:groovy-xml:3.0.17=testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-xml:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.codehaus.groovy:groovy:2.5.14=codenarc -org.codehaus.groovy:groovy:3.0.17=testCompileClasspath,testRuntimeClasspath -org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,testAnnotationProcessor +org.codehaus.groovy:groovy:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor org.codenarc:CodeNarc:2.2.0=codenarc org.dom4j:dom4j:2.1.3=spotbugs -org.eclipse.jetty:jetty-http:9.2.30.v20200428=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-io:9.2.30.v20200428=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-server:9.2.30.v20200428=testCompileClasspath,testRuntimeClasspath -org.eclipse.jetty:jetty-util:9.2.30.v20200428=testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-http:9.2.30.v20200428=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-io:9.2.30.v20200428=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-server:9.2.30.v20200428=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-util:9.2.30.v20200428=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath org.gmetrics:GMetrics:1.1=codenarc -org.hamcrest:hamcrest-core:1.3=testCompileClasspath,testRuntimeClasspath -org.hamcrest:hamcrest:2.2=testCompileClasspath,testRuntimeClasspath -org.jctools:jctools-core:3.3.0=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-api:5.9.2=testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter-engine:5.9.2=testRuntimeClasspath -org.junit.jupiter:junit-jupiter-params:5.9.2=testCompileClasspath,testRuntimeClasspath -org.junit.jupiter:junit-jupiter:5.9.2=testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-commons:1.9.2=testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-engine:1.9.2=testCompileClasspath,testRuntimeClasspath -org.junit.platform:junit-platform-launcher:1.9.2=testRuntimeClasspath -org.junit.platform:junit-platform-runner:1.9.2=testRuntimeClasspath -org.junit.platform:junit-platform-suite-api:1.9.2=testRuntimeClasspath -org.junit.platform:junit-platform-suite-commons:1.9.2=testRuntimeClasspath -org.junit:junit-bom:5.9.1=spotbugs -org.junit:junit-bom:5.9.2=testCompileClasspath,testRuntimeClasspath -org.mockito:mockito-core:4.8.1=testCompileClasspath,testRuntimeClasspath -org.mockito:mockito-junit-jupiter:4.8.1=testCompileClasspath,testRuntimeClasspath -org.objenesis:objenesis:3.3=testCompileClasspath,testRuntimeClasspath -org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testRuntimeClasspath -org.ow2.asm:asm-analysis:9.2=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.hamcrest:hamcrest-core:1.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.hamcrest:hamcrest:2.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jctools:jctools-core:3.3.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-api:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-params:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-commons:1.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-engine:1.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-runner:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-suite-commons:1.9.2=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.junit:junit-bom:5.9.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-core:4.0.0=testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-core:4.5.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.mockito:mockito-junit-jupiter:4.0.0=testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-junit-jupiter:4.5.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.objenesis:objenesis:3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.opentest4j:opentest4j:1.2.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath org.ow2.asm:asm-analysis:9.4=spotbugs -org.ow2.asm:asm-commons:9.2=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-commons:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath org.ow2.asm:asm-commons:9.4=spotbugs -org.ow2.asm:asm-tree:9.2=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-tree:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath org.ow2.asm:asm-tree:9.4=spotbugs -org.ow2.asm:asm-util:9.2=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-util:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath org.ow2.asm:asm-util:9.4=spotbugs -org.ow2.asm:asm:9.1=testCompileClasspath -org.ow2.asm:asm:9.2=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm:9.1=latestDepTestCompileClasspath,testCompileClasspath +org.ow2.asm:asm:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath org.ow2.asm:asm:9.4=spotbugs -org.skyscreamer:jsonassert:1.5.1=testCompileClasspath,testRuntimeClasspath -org.slf4j:jcl-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath -org.slf4j:jul-to-slf4j:2.0.4=testCompileClasspath,testRuntimeClasspath -org.slf4j:log4j-over-slf4j:1.7.30=testCompileClasspath,testRuntimeClasspath -org.slf4j:slf4j-api:1.7.30=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath +org.skyscreamer:jsonassert:1.5.0=testCompileClasspath,testRuntimeClasspath +org.skyscreamer:jsonassert:1.5.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.slf4j:jcl-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:jul-to-slf4j:1.7.32=testCompileClasspath,testRuntimeClasspath +org.slf4j:jul-to-slf4j:1.7.36=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.slf4j:log4j-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.30=compileClasspath,instrumentPluginClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath +org.slf4j:slf4j-api:1.7.32=testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.36=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath org.slf4j:slf4j-api:2.0.0=spotbugs,spotbugsSlf4j -org.slf4j:slf4j-api:2.0.4=testCompileClasspath,testRuntimeClasspath org.slf4j:slf4j-simple:2.0.0=spotbugsSlf4j -org.spockframework:spock-core:2.2-groovy-3.0=testCompileClasspath,testRuntimeClasspath -org.spockframework:spock-junit4:2.2-groovy-3.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-autoconfigure:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-starter-jdbc:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-starter-json:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-starter-logging:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-starter-security:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-starter-test:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-starter-tomcat:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-starter-web:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-starter:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-test-autoconfigure:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot-test:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.boot:spring-boot:3.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.security:spring-security-config:6.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.security:spring-security-core:5.5.0=compileClasspath,main_java17CompileClasspath -org.springframework.security:spring-security-core:6.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.security:spring-security-crypto:5.5.0=compileClasspath,main_java17CompileClasspath -org.springframework.security:spring-security-crypto:6.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework.security:spring-security-web:6.0.0=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-aop:5.3.7=compileClasspath,main_java17CompileClasspath -org.springframework:spring-aop:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-beans:5.3.7=compileClasspath,main_java17CompileClasspath -org.springframework:spring-beans:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-context:5.3.7=compileClasspath,main_java17CompileClasspath -org.springframework:spring-context:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-core:5.3.7=compileClasspath,main_java17CompileClasspath -org.springframework:spring-core:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-expression:5.3.7=compileClasspath,main_java17CompileClasspath -org.springframework:spring-expression:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-jcl:5.3.7=compileClasspath,main_java17CompileClasspath -org.springframework:spring-jcl:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-jdbc:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-test:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-tx:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-web:6.0.2=testCompileClasspath,testRuntimeClasspath -org.springframework:spring-webmvc:6.0.2=testCompileClasspath,testRuntimeClasspath -org.testng:testng:7.5=testRuntimeClasspath -org.webjars:jquery:3.5.1=testRuntimeClasspath +org.spockframework:spock-core:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.spockframework:spock-junit4:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-autoconfigure:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-autoconfigure:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-json:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-json:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-logging:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-logging:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-security:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-security:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-test:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-test:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-tomcat:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-tomcat:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-web:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-web:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-test-autoconfigure:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-test-autoconfigure:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-test:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-test:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot:2.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot:2.7.18=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.security:spring-security-config:5.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.security:spring-security-config:5.7.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.security:spring-security-core:5.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.security:spring-security-core:5.7.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.security:spring-security-core:5.8.2=compileClasspath +org.springframework.security:spring-security-crypto:5.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.security:spring-security-crypto:5.7.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.security:spring-security-crypto:5.8.2=compileClasspath +org.springframework.security:spring-security-web:5.6.0=testCompileClasspath,testRuntimeClasspath +org.springframework.security:spring-security-web:5.7.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-aop:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-aop:5.3.25=compileClasspath +org.springframework:spring-aop:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-beans:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-beans:5.3.25=compileClasspath +org.springframework:spring-beans:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-context:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-context:5.3.25=compileClasspath +org.springframework:spring-context:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-core:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-core:5.3.25=compileClasspath +org.springframework:spring-core:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-expression:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-expression:5.3.25=compileClasspath +org.springframework:spring-expression:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-jcl:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-jcl:5.3.25=compileClasspath +org.springframework:spring-jcl:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-test:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-test:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-web:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-web:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-webmvc:5.3.13=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-webmvc:5.3.31=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.testng:testng:7.5=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.webjars:jquery:3.5.1=latestDepTestRuntimeClasspath,testRuntimeClasspath org.xmlresolver:xmlresolver:4.4.3=spotbugs -org.xmlunit:xmlunit-core:2.9.0=testCompileClasspath,testRuntimeClasspath -org.yaml:snakeyaml:1.33=testCompileClasspath,testRuntimeClasspath +org.xmlunit:xmlunit-core:2.8.3=testCompileClasspath,testRuntimeClasspath +org.xmlunit:xmlunit-core:2.9.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.yaml:snakeyaml:1.29=testCompileClasspath,testRuntimeClasspath +org.yaml:snakeyaml:1.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath xml-apis:xml-apis:1.4.01=spotbugs -empty=main_java17AnnotationProcessor,spotbugsPlugins +empty=spotbugsPlugins diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/AppSecDeferredContext.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/AppSecDeferredContext.java new file mode 100644 index 00000000000..bfdea675ef9 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/AppSecDeferredContext.java @@ -0,0 +1,22 @@ +package datadog.trace.instrumentation.springsecurity5; + +import java.util.function.Supplier; +import org.springframework.security.core.context.SecurityContext; + +public class AppSecDeferredContext implements Supplier { + + private final Supplier delegate; + + public AppSecDeferredContext(final Supplier delegate) { + this.delegate = delegate; + } + + @Override + public SecurityContext get() { + SecurityContext context = delegate.get(); + if (context != null) { + SpringSecurityUserEventDecorator.DECORATE.onUser(context.getAuthentication()); + } + return context; + } +} diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/AuthenticationProviderInstrumentation.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/AuthenticationProviderInstrumentation.java index 2eedc42e624..77d1e3b4531 100644 --- a/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/AuthenticationProviderInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/AuthenticationProviderInstrumentation.java @@ -10,8 +10,12 @@ import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.bootstrap.ActiveSubsystems; +import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; @AutoService(InstrumenterModule.class) public class AuthenticationProviderInstrumentation extends InstrumenterModule.AppSec @@ -46,6 +50,19 @@ public void methodAdvice(MethodTransformer transformer) { .and(takesArgument(0, named("org.springframework.security.core.Authentication"))) .and(returns(named("org.springframework.security.core.Authentication"))) .and(isPublic()), - packageName + ".AuthenticationProviderAdvice"); + getClass().getName() + "$AuthenticationProviderAdvice"); + } + + public static class AuthenticationProviderAdvice { + + @Advice.OnMethodExit(onThrowable = AuthenticationException.class, suppress = Throwable.class) + public static void onExit( + @Advice.Argument(value = 0, readOnly = false) Authentication authentication, + @Advice.Return final Authentication result, + @Advice.Thrown final AuthenticationException throwable) { + if (ActiveSubsystems.APPSEC_ACTIVE) { + SpringSecurityUserEventDecorator.DECORATE.onLogin(authentication, throwable, result); + } + } } } diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/SecurityContextHolderInstrumentation.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/SecurityContextHolderInstrumentation.java new file mode 100644 index 00000000000..31cc383c28a --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/SecurityContextHolderInstrumentation.java @@ -0,0 +1,90 @@ +package datadog.trace.instrumentation.springsecurity5; + +import static datadog.trace.agent.tooling.bytebuddy.matcher.HierarchyMatchers.implementsInterface; +import static datadog.trace.agent.tooling.bytebuddy.matcher.NameMatchers.named; +import static net.bytebuddy.matcher.ElementMatchers.isMethod; +import static net.bytebuddy.matcher.ElementMatchers.isPublic; +import static net.bytebuddy.matcher.ElementMatchers.takesArgument; +import static net.bytebuddy.matcher.ElementMatchers.takesArguments; + +import com.google.auto.service.AutoService; +import datadog.trace.agent.tooling.Instrumenter; +import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.bootstrap.ActiveSubsystems; +import java.util.function.Supplier; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.matcher.ElementMatcher; +import org.springframework.security.core.context.SecurityContext; + +@AutoService(InstrumenterModule.class) +public class SecurityContextHolderInstrumentation extends InstrumenterModule.AppSec + implements Instrumenter.ForTypeHierarchy { + + public SecurityContextHolderInstrumentation() { + super("spring-security"); + } + + @Override + public String hierarchyMarkerType() { + return "org.springframework.security.core.context.SecurityContextHolderStrategy"; + } + + @Override + public ElementMatcher hierarchyMatcher() { + return implementsInterface(named(hierarchyMarkerType())); + } + + @Override + public String[] helperClassNames() { + return new String[] { + "datadog.trace.instrumentation.springsecurity5.SpringSecurityUserEventDecorator", + "datadog.trace.instrumentation.springsecurity5.AppSecDeferredContext" + }; + } + + @Override + public void methodAdvice(MethodTransformer transformer) { + transformer.applyAdvice( + isMethod() + .and(named("setContext")) + .and(takesArguments(1)) + .and( + takesArgument( + 0, named("org.springframework.security.core.context.SecurityContext"))) + .and(isPublic()), + getClass().getName() + "$SetSecurityContextAdvice"); + transformer.applyAdvice( + isMethod().and(named("setDeferredContext")).and(takesArguments(1)).and(isPublic()), + getClass().getName() + "$SetDeferredSecurityContextAdvice"); + } + + public static class SetSecurityContextAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter(@Advice.Argument(0) final SecurityContext context) { + if (context == null) { + return; + } + if (!ActiveSubsystems.APPSEC_ACTIVE) { + return; + } + SpringSecurityUserEventDecorator.DECORATE.onUser(context.getAuthentication()); + } + } + + public static class SetDeferredSecurityContextAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter( + @Advice.Argument(value = 0, readOnly = false) Supplier deferred) { + if (deferred == null) { + return; + } + if (!ActiveSubsystems.APPSEC_ACTIVE) { + return; + } + deferred = new AppSecDeferredContext(deferred); + } + } +} diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/SpringSecurityUserEventDecorator.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/SpringSecurityUserEventDecorator.java similarity index 91% rename from dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/SpringSecurityUserEventDecorator.java rename to dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/SpringSecurityUserEventDecorator.java index 175470b5ea8..25c20548ec0 100644 --- a/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/SpringSecurityUserEventDecorator.java +++ b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/SpringSecurityUserEventDecorator.java @@ -111,6 +111,25 @@ public void onLogin(Authentication authentication, Throwable throwable, Authenti } } + public void onUser(final Authentication authentication) { + if (authentication == null) { + return; + } + + final AppSecEventTracker tracker = AppSecEventTracker.getEventTracker(); + if (tracker == null) { + return; + } + + if (shouldSkipAuthentication(authentication)) { + return; + } + + UserIdCollectionMode mode = UserIdCollectionMode.get(); + String userId = authentication.getName(); + tracker.onUserEvent(mode, userId); + } + private static boolean shouldSkipAuthentication(final Authentication authentication) { if (authentication instanceof UsernamePasswordAuthenticationToken) { return false; diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/UserDetailsManagerInstrumentation.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/UserDetailsManagerInstrumentation.java index 1545edd41e0..cdbefae8760 100644 --- a/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/UserDetailsManagerInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/UserDetailsManagerInstrumentation.java @@ -9,8 +9,11 @@ import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; +import datadog.trace.bootstrap.ActiveSubsystems; +import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; +import org.springframework.security.core.userdetails.UserDetails; @AutoService(InstrumenterModule.class) public class UserDetailsManagerInstrumentation extends InstrumenterModule.AppSec @@ -46,6 +49,18 @@ public void methodAdvice(MethodTransformer transformer) { takesArgument( 0, named("org.springframework.security.core.userdetails.UserDetails"))) .and(isPublic()), - packageName + ".UserDetailsManagerAdvice"); + getClass().getName() + "$UserDetailsManagerAdvice"); + } + + public static class UserDetailsManagerAdvice { + + @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) + public static void onExit( + @Advice.Argument(value = 0, readOnly = false) UserDetails user, + @Advice.Thrown Throwable throwable) { + if (ActiveSubsystems.APPSEC_ACTIVE) { + SpringSecurityUserEventDecorator.DECORATE.onSignup(user, throwable); + } + } } } diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/UsernameNotFoundExceptionInstrumentation.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/UsernameNotFoundExceptionInstrumentation.java index a2bf67c779a..38cd80fc061 100644 --- a/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/UsernameNotFoundExceptionInstrumentation.java +++ b/dd-java-agent/instrumentation/spring-security-5/src/main/java/datadog/trace/instrumentation/springsecurity5/UsernameNotFoundExceptionInstrumentation.java @@ -9,6 +9,7 @@ import com.google.auto.service.AutoService; import datadog.trace.agent.tooling.Instrumenter; import datadog.trace.agent.tooling.InstrumenterModule; +import net.bytebuddy.asm.Advice; import net.bytebuddy.description.type.TypeDescription; import net.bytebuddy.matcher.ElementMatcher; @@ -41,6 +42,14 @@ public String[] helperClassNames() { public void methodAdvice(MethodTransformer transformer) { transformer.applyAdvice( isConstructor().and(takesArgument(0, named("java.lang.String"))).and(isPublic()), - packageName + ".UsernameNotFoundExceptionAdvice"); + getClass().getName() + "$UsernameNotFoundExceptionAdvice"); + } + + public static class UsernameNotFoundExceptionAdvice { + + @Advice.OnMethodEnter(suppress = Throwable.class) + public static void onEnter() { + SpringSecurityUserEventDecorator.DECORATE.onUserNotFound(); + } } } diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/AuthenticationProviderAdvice.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/AuthenticationProviderAdvice.java deleted file mode 100644 index 9afaa255ff0..00000000000 --- a/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/AuthenticationProviderAdvice.java +++ /dev/null @@ -1,19 +0,0 @@ -package datadog.trace.instrumentation.springsecurity5; - -import datadog.trace.bootstrap.ActiveSubsystems; -import net.bytebuddy.asm.Advice; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.AuthenticationException; - -public class AuthenticationProviderAdvice { - - @Advice.OnMethodExit(onThrowable = AuthenticationException.class, suppress = Throwable.class) - public static void onExit( - @Advice.Argument(value = 0, readOnly = false) Authentication authentication, - @Advice.Return final Authentication result, - @Advice.Thrown final AuthenticationException throwable) { - if (ActiveSubsystems.APPSEC_ACTIVE) { - SpringSecurityUserEventDecorator.DECORATE.onLogin(authentication, throwable, result); - } - } -} diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/UserDetailsManagerAdvice.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/UserDetailsManagerAdvice.java deleted file mode 100644 index fe36885e437..00000000000 --- a/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/UserDetailsManagerAdvice.java +++ /dev/null @@ -1,17 +0,0 @@ -package datadog.trace.instrumentation.springsecurity5; - -import datadog.trace.bootstrap.ActiveSubsystems; -import net.bytebuddy.asm.Advice; -import org.springframework.security.core.userdetails.UserDetails; - -public class UserDetailsManagerAdvice { - - @Advice.OnMethodExit(onThrowable = Throwable.class, suppress = Throwable.class) - public static void onExit( - @Advice.Argument(value = 0, readOnly = false) UserDetails user, - @Advice.Thrown Throwable throwable) { - if (ActiveSubsystems.APPSEC_ACTIVE) { - SpringSecurityUserEventDecorator.DECORATE.onSignup(user, throwable); - } - } -} diff --git a/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/UsernameNotFoundExceptionAdvice.java b/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/UsernameNotFoundExceptionAdvice.java deleted file mode 100644 index f3d24b75ea0..00000000000 --- a/dd-java-agent/instrumentation/spring-security-5/src/main/java17/datadog/trace/instrumentation/springsecurity5/UsernameNotFoundExceptionAdvice.java +++ /dev/null @@ -1,11 +0,0 @@ -package datadog.trace.instrumentation.springsecurity5; - -import net.bytebuddy.asm.Advice; - -public class UsernameNotFoundExceptionAdvice { - - @Advice.OnMethodEnter(suppress = Throwable.class) - public static void onEnter() { - SpringSecurityUserEventDecorator.DECORATE.onUserNotFound(); - } -} diff --git a/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/SecurityConfig.groovy b/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/SecurityConfig.groovy index e865ef18e5c..d5ce025ad32 100644 --- a/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/SecurityConfig.groovy +++ b/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/SecurityConfig.groovy @@ -2,20 +2,18 @@ package datadog.trace.instrumentation.springsecurity5 import custom.CustomAuthenticationFilter import custom.CustomAuthenticationProvider -import org.springframework.boot.jdbc.DataSourceBuilder import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.security.authentication.AuthenticationManager 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.configurers.AbstractHttpConfigurer -import org.springframework.security.provisioning.JdbcUserDetailsManager +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.provisioning.InMemoryUserDetailsManager import org.springframework.security.provisioning.UserDetailsManager import org.springframework.security.web.SecurityFilterChain import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter -import javax.sql.DataSource - import static datadog.trace.instrumentation.springsecurity5.SecurityConfig.CustomDsl.customDsl @Configuration @@ -26,28 +24,25 @@ class SecurityConfig { SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http.apply(customDsl()) http - .authorizeHttpRequests( - (requests) -> requests - .requestMatchers("/", "/success", "/register", "/login", "/custom").permitAll() - .anyRequest().authenticated()) .csrf().disable() .formLogin((form) -> form.loginPage("/login").permitAll()) + .authorizeRequests() + .antMatchers("/", "/success", "/register", "/login", "/custom").permitAll() + .anyRequest().authenticated() return http.build() } - @Bean - DataSource getDataSource() { - DataSourceBuilder dataSourceBuilder = DataSourceBuilder.create() - dataSourceBuilder.driverClassName("org.h2.Driver") - dataSourceBuilder.url("jdbc:h2:mem:authDB;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=RUNSCRIPT FROM 'classpath:schema.sql';") - dataSourceBuilder.username("SA") - dataSourceBuilder.password("") - return dataSourceBuilder.build() - } - @Bean UserDetailsManager userDetailsService() { - return new JdbcUserDetailsManager(dataSource) + return new InMemoryUserDetailsManager() { + @Override + void createUser(UserDetails user) { + if (user.username == 'cant_create_me') { + throw new IllegalArgumentException('cannot create user') + } + super.createUser(user) + } + } } static class CustomDsl extends AbstractHttpConfigurer { diff --git a/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/SpringBootBasedTest.groovy b/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/SpringBootBasedTest.groovy index a9262731ef3..96f9c21836c 100644 --- a/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/SpringBootBasedTest.groovy +++ b/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/SpringBootBasedTest.groovy @@ -15,10 +15,13 @@ import org.springframework.boot.web.servlet.context.ServletWebServerApplicationC import org.springframework.context.ConfigurableApplicationContext import spock.lang.Shared -import static datadog.trace.instrumentation.springsecurity5.TestEndpoint.LOGIN +import static datadog.trace.agent.test.utils.OkHttpUtils.clientBuilder +import static datadog.trace.agent.test.utils.OkHttpUtils.cookieJar import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace import static datadog.trace.instrumentation.springsecurity5.TestEndpoint.CUSTOM +import static datadog.trace.instrumentation.springsecurity5.TestEndpoint.LOGIN import static datadog.trace.instrumentation.springsecurity5.TestEndpoint.REGISTER +import static datadog.trace.instrumentation.springsecurity5.TestEndpoint.SUCCESS import static datadog.trace.instrumentation.springsecurity5.TestEndpoint.UNKNOWN import static datadog.trace.instrumentation.springsecurity5.TestEndpoint.NOT_FOUND @@ -213,7 +216,7 @@ class SpringBootBasedTest extends AppSecHttpServerTest - (1..length).collect { Character.valueOf((char) (random.nextInt(26) + (char)'a')) } - }.join() + void 'test user event'() { + setup: + def client = clientBuilder().cookieJar(cookieJar()).followRedirects(false).build() + def formBody = new FormBody.Builder() + .add("username", "admin") + .add("password", "admin") + .build() + + def loginRequest = request(LOGIN, "POST", formBody).build() + def loginResponse = client.newCall(loginRequest).execute() + assert loginResponse.code() == LOGIN.status + assert loginResponse.body().string() == LOGIN.body + TEST_WRITER.waitForTraces(1) + TEST_WRITER.start() // clear all traces + + when: + def request = request(SUCCESS, "GET", null).build() + def response = client.newCall(request).execute() + TEST_WRITER.waitForTraces(1) + def span = TEST_WRITER.flatten().first() as DDSpan + + then: + response.code() == SUCCESS.status + response.body().string() == SUCCESS.body + span.getResourceName().toString() == 'GET /success' + !span.getTags().isEmpty() + span.getTag("usr.id") == 'admin' + span.getTag("_dd.appsec.user.collection_mode") == 'ident' } } diff --git a/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/TestEndpoint.groovy b/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/TestEndpoint.groovy index bb6d223a7a7..3a558355471 100644 --- a/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/TestEndpoint.groovy +++ b/dd-java-agent/instrumentation/spring-security-5/src/test/groovy/datadog/trace/instrumentation/springsecurity5/TestEndpoint.groovy @@ -6,6 +6,7 @@ enum TestEndpoint { NOT_FOUND("not-found", 404, "not found"), UNKNOWN("", 451, null), // This needs to have a valid status code CUSTOM("custom", 302, ""), + SUCCESS("success", 200, ""), private final String path private final String rawPath diff --git a/dd-java-agent/instrumentation/spring-security-5/src/test/java/custom/CustomAuthenticationFilter.java b/dd-java-agent/instrumentation/spring-security-5/src/test/java/custom/CustomAuthenticationFilter.java index b3ec62a572b..f63ccdc574d 100644 --- a/dd-java-agent/instrumentation/spring-security-5/src/test/java/custom/CustomAuthenticationFilter.java +++ b/dd-java-agent/instrumentation/spring-security-5/src/test/java/custom/CustomAuthenticationFilter.java @@ -1,9 +1,9 @@ package custom; -import jakarta.servlet.ServletException; -import jakarta.servlet.http.HttpServletRequest; -import jakarta.servlet.http.HttpServletResponse; import java.io.IOException; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; diff --git a/dd-java-agent/instrumentation/spring-security-5/src/test/resources/schema.sql b/dd-java-agent/instrumentation/spring-security-5/src/test/resources/schema.sql deleted file mode 100644 index f7a9a7728ca..00000000000 --- a/dd-java-agent/instrumentation/spring-security-5/src/test/resources/schema.sql +++ /dev/null @@ -1,30 +0,0 @@ -create table IF NOT EXISTS users( - username varchar_ignorecase(50) not null primary key, - password varchar_ignorecase(500) not null, - enabled boolean not null -); - -create table IF NOT EXISTS authorities ( - username varchar_ignorecase(50) not null, - authority varchar_ignorecase(50) not null, - constraint fk_authorities_users foreign key(username) references users(username) -); -create unique index IF NOT EXISTS ix_auth_username on authorities (username,authority); - -create table IF NOT EXISTS groups ( - id bigint generated by default as identity(start with 0) primary key, - group_name varchar_ignorecase(50) not null -); - -create table IF NOT EXISTS group_authorities ( - group_id bigint not null, - authority varchar(50) not null, - constraint fk_group_authorities_group foreign key(group_id) references groups(id) -); - -create table IF NOT EXISTS group_members ( - id bigint generated by default as identity(start with 0) primary key, - username varchar(50) not null, - group_id bigint not null, - constraint fk_group_members_group foreign key(group_id) references groups(id) -); \ No newline at end of file diff --git a/dd-java-agent/instrumentation/spring-security-6/build.gradle b/dd-java-agent/instrumentation/spring-security-6/build.gradle new file mode 100644 index 00000000000..e746ed3f9c5 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/build.gradle @@ -0,0 +1,32 @@ +ext { + minJavaVersionForTests = JavaVersion.VERSION_17 +} + +apply from: "$rootDir/gradle/java.gradle" +addTestSuiteForDir('latestDepTest', 'test') + +final springBootVersion = '3.0.0' + +tasks.withType(AbstractCompile).configureEach { + setJavaVersion(it, 17) +} + +tasks.withType(GroovyCompile).configureEach { + javaLauncher = getJavaLauncherFor(17) +} + +dependencies { + + testImplementation testFixtures(project(':dd-java-agent:appsec')) + testImplementation project(':dd-java-agent:instrumentation:spring-security-5') + testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: springBootVersion + testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: springBootVersion + testImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: springBootVersion + + latestDepTestImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-test', version: '+' + latestDepTestImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-web', version: '+' + latestDepTestImplementation group: 'org.springframework.boot', name: 'spring-boot-starter-security', version: '+' + + testRuntimeOnly project(':dd-java-agent:instrumentation:tomcat-appsec-6') + testRuntimeOnly project(':dd-java-agent:instrumentation:tomcat-5.5') +} diff --git a/dd-java-agent/instrumentation/spring-security-6/gradle.lockfile b/dd-java-agent/instrumentation/spring-security-6/gradle.lockfile new file mode 100644 index 00000000000..0f542362a9c --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/gradle.lockfile @@ -0,0 +1,272 @@ +# This is a Gradle generated file for dependency locking. +# Manual edits can break the build and are not advised. +# This file is expected to be part of source control. +cafe.cryptography:curve25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +cafe.cryptography:ed25519-elisabeth:0.1.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +ch.qos.logback:logback-classic:1.4.5=testCompileClasspath,testRuntimeClasspath +ch.qos.logback:logback-classic:1.5.7=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +ch.qos.logback:logback-core:1.4.5=testCompileClasspath,testRuntimeClasspath +ch.qos.logback:logback-core:1.5.7=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.beust:jcommander:1.78=latestDepTestRuntimeClasspath,testRuntimeClasspath +com.blogspot.mydailyjava:weak-lock-free:0.17=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okhttp3:okhttp:3.12.15=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq.okio:okio:1.17.6=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:dd-javac-plugin-client:0.1.7=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.datadoghq:java-dogstatsd-client:4.4.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.datadoghq:sketches-java:0.8.3=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-annotations:2.14.1=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-annotations:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.core:jackson-core:2.14.1=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-core:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.core:jackson-databind:2.14.1=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.core:jackson-databind:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.14.1=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.14.1=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson.module:jackson-module-parameter-names:2.14.1=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson.module:jackson-module-parameter-names:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.fasterxml.jackson:jackson-bom:2.14.1=testCompileClasspath,testRuntimeClasspath +com.fasterxml.jackson:jackson-bom:2.17.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.github.javaparser:javaparser-core:3.25.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.github.jnr:jffi:1.3.13=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-a64asm:1.0.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-constants:0.10.4=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-enxio:0.32.17=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-ffi:2.2.16=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-posix:3.1.19=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-unixsocket:0.38.22=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.jnr:jnr-x86asm:1.0.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.2.0=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.github.spotbugs:spotbugs-annotations:4.7.3=spotbugs +com.github.spotbugs:spotbugs:4.7.3=spotbugs +com.github.stefanbirkner:system-rules:1.19.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.auto.service:auto-service-annotations:1.0-rc7=annotationProcessor,compileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,testAnnotationProcessor,testCompileClasspath +com.google.auto.service:auto-service:1.0-rc7=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.auto:auto-common:0.10=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.code.findbugs:jsr305:3.0.2=annotationProcessor,compileClasspath,latestDepTestAnnotationProcessor,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testAnnotationProcessor,testCompileClasspath,testRuntimeClasspath +com.google.code.gson:gson:2.9.1=spotbugs +com.google.errorprone:error_prone_annotations:2.2.0=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:failureaccess:1.0.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:guava:20.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.google.guava:guava:27.0.1-jre=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.j2objc:j2objc-annotations:1.1=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +com.google.re2j:re2j:1.7=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +com.jayway.jsonpath:json-path:2.7.0=testCompileClasspath,testRuntimeClasspath +com.jayway.jsonpath:json-path:2.9.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +com.squareup.moshi:moshi:1.11.0=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:logging-interceptor:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okhttp3:okhttp:3.12.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +com.squareup.okio:okio:1.17.5=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +com.thoughtworks.qdox:qdox:1.12.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +com.vaadin.external.google:android-json:0.0.20131108.vaadin1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +commons-codec:commons-codec:1.15=spotbugs +commons-fileupload:commons-fileupload:1.5=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +commons-io:commons-io:2.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +de.thetaphi:forbiddenapis:3.1=compileClasspath +info.picocli:picocli:4.6.3=latestDepTestRuntimeClasspath,testRuntimeClasspath +io.micrometer:micrometer-commons:1.10.1=testCompileClasspath,testRuntimeClasspath +io.micrometer:micrometer-commons:1.12.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.micrometer:micrometer-observation:1.10.1=testCompileClasspath,testRuntimeClasspath +io.micrometer:micrometer-observation:1.12.9=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +io.sqreen:libsqreen:11.0.0=latestDepTestRuntimeClasspath,testRuntimeClasspath +jakarta.activation:jakarta.activation-api:2.1.0=testCompileClasspath,testRuntimeClasspath +jakarta.activation:jakarta.activation-api:2.1.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +jakarta.annotation:jakarta.annotation-api:2.1.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +jakarta.xml.bind:jakarta.xml.bind-api:4.0.0=testCompileClasspath,testRuntimeClasspath +jakarta.xml.bind:jakarta.xml.bind-api:4.0.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +javax.servlet:javax.servlet-api:3.1.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +jaxen:jaxen:1.2.0=spotbugs +jline:jline:2.14.6=latestDepTestRuntimeClasspath,testRuntimeClasspath +junit:junit-dep:4.11=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +junit:junit:4.13.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy-agent:1.14.18=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.bytebuddy:byte-buddy:1.14.18=compileClasspath,instrumentPluginClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testCompileClasspath,testRuntimeClasspath +net.java.dev.jna:jna-platform:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.java.dev.jna:jna:5.8.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +net.jcip:jcip-annotations:1.0=compileClasspath,latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,spotbugs,testCompileClasspath,testRuntimeClasspath +net.minidev:accessors-smart:2.4.7=testCompileClasspath,testRuntimeClasspath +net.minidev:accessors-smart:2.5.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +net.minidev:json-smart:2.4.7=testCompileClasspath,testRuntimeClasspath +net.minidev:json-smart:2.5.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +net.sf.saxon:Saxon-HE:11.4=spotbugs +org.apache.ant:ant-antlr:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant-antlr:1.9.15=codenarc +org.apache.ant:ant-junit:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant-junit:1.9.15=codenarc +org.apache.ant:ant-launcher:1.10.12=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.apache.ant:ant:1.10.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.apache.bcel:bcel:6.5.0=spotbugs +org.apache.commons:commons-lang3:3.12.0=spotbugs +org.apache.commons:commons-text:1.10.0=spotbugs +org.apache.httpcomponents.client5:httpclient5:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5-h2:5.1.3=spotbugs +org.apache.httpcomponents.core5:httpcore5:5.1.3=spotbugs +org.apache.logging.log4j:log4j-api:2.19.0=spotbugs,testCompileClasspath,testRuntimeClasspath +org.apache.logging.log4j:log4j-api:2.23.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.logging.log4j:log4j-core:2.19.0=spotbugs +org.apache.logging.log4j:log4j-to-slf4j:2.19.0=testCompileClasspath,testRuntimeClasspath +org.apache.logging.log4j:log4j-to-slf4j:2.23.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-core:10.1.1=testCompileClasspath,testRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-core:10.1.28=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-el:10.1.1=testCompileClasspath,testRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-el:10.1.28=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-websocket:10.1.1=testCompileClasspath,testRuntimeClasspath +org.apache.tomcat.embed:tomcat-embed-websocket:10.1.28=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.apiguardian:apiguardian-api:1.1.2=latestDepTestCompileClasspath,testCompileClasspath +org.assertj:assertj-core:3.23.1=testCompileClasspath,testRuntimeClasspath +org.assertj:assertj-core:3.25.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.awaitility:awaitility:4.2.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.checkerframework:checker-qual:2.5.2=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +org.codehaus.groovy:groovy-all:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-ant:2.5.14=codenarc +org.codehaus.groovy:groovy-ant:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-astbuilder:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-cli-picocli:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-console:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-datetime:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-docgenerator:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovydoc:2.5.14=codenarc +org.codehaus.groovy:groovy-groovydoc:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-groovysh:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jmx:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-json:2.5.14=codenarc +org.codehaus.groovy:groovy-json:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-jsr223:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-macro:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-nio:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-servlet:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-sql:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-swing:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-templates:2.5.14=codenarc +org.codehaus.groovy:groovy-templates:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test-junit5:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-test:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-testng:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy-xml:2.5.14=codenarc +org.codehaus.groovy:groovy-xml:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.groovy:groovy:2.5.14=codenarc +org.codehaus.groovy:groovy:3.0.17=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.codehaus.mojo:animal-sniffer-annotations:1.17=annotationProcessor,latestDepTestAnnotationProcessor,testAnnotationProcessor +org.codenarc:CodeNarc:2.2.0=codenarc +org.dom4j:dom4j:2.1.3=spotbugs +org.eclipse.jetty:jetty-http:9.2.30.v20200428=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-io:9.2.30.v20200428=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-server:9.2.30.v20200428=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.eclipse.jetty:jetty-util:9.2.30.v20200428=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.gmetrics:GMetrics:1.1=codenarc +org.hamcrest:hamcrest-core:1.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.hamcrest:hamcrest:2.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.jctools:jctools-core:3.3.0=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-api:5.10.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.junit.jupiter:junit-jupiter-api:5.9.2=testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.10.3=latestDepTestRuntimeClasspath +org.junit.jupiter:junit-jupiter-engine:5.9.2=testRuntimeClasspath +org.junit.jupiter:junit-jupiter-params:5.10.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.junit.jupiter:junit-jupiter-params:5.9.2=testCompileClasspath,testRuntimeClasspath +org.junit.jupiter:junit-jupiter:5.10.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.junit.jupiter:junit-jupiter:5.9.2=testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-commons:1.10.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.junit.platform:junit-platform-commons:1.9.2=testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-engine:1.10.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.junit.platform:junit-platform-engine:1.9.2=testCompileClasspath,testRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.10.3=latestDepTestRuntimeClasspath +org.junit.platform:junit-platform-launcher:1.9.2=testRuntimeClasspath +org.junit.platform:junit-platform-runner:1.10.3=latestDepTestRuntimeClasspath +org.junit.platform:junit-platform-runner:1.9.2=testRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.10.3=latestDepTestRuntimeClasspath +org.junit.platform:junit-platform-suite-api:1.9.2=testRuntimeClasspath +org.junit.platform:junit-platform-suite-commons:1.10.3=latestDepTestRuntimeClasspath +org.junit.platform:junit-platform-suite-commons:1.9.2=testRuntimeClasspath +org.junit:junit-bom:5.10.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.junit:junit-bom:5.9.2=testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-core:4.8.1=testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-core:5.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.mockito:mockito-junit-jupiter:4.8.1=testCompileClasspath,testRuntimeClasspath +org.mockito:mockito-junit-jupiter:5.11.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.objenesis:objenesis:3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.opentest4j:opentest4j:1.2.0=testCompileClasspath,testRuntimeClasspath +org.opentest4j:opentest4j:1.3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.ow2.asm:asm-analysis:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-analysis:9.4=spotbugs +org.ow2.asm:asm-commons:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-commons:9.4=spotbugs +org.ow2.asm:asm-tree:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-tree:9.4=spotbugs +org.ow2.asm:asm-util:9.2=instrumentPluginClasspath,latestDepTestRuntimeClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm-util:9.4=spotbugs +org.ow2.asm:asm:9.1=testCompileClasspath +org.ow2.asm:asm:9.2=instrumentPluginClasspath,main_java17RuntimeClasspath,muzzleTooling,runtimeClasspath,testRuntimeClasspath +org.ow2.asm:asm:9.4=spotbugs +org.ow2.asm:asm:9.6=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.skyscreamer:jsonassert:1.5.1=testCompileClasspath,testRuntimeClasspath +org.skyscreamer:jsonassert:1.5.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.slf4j:jcl-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:jul-to-slf4j:2.0.16=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.slf4j:jul-to-slf4j:2.0.4=testCompileClasspath,testRuntimeClasspath +org.slf4j:log4j-over-slf4j:1.7.30=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-api:1.7.30=compileClasspath,instrumentPluginClasspath,main_java17CompileClasspath,main_java17RuntimeClasspath,muzzleBootstrap,muzzleTooling,runtimeClasspath +org.slf4j:slf4j-api:2.0.0=spotbugs,spotbugsSlf4j +org.slf4j:slf4j-api:2.0.16=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.slf4j:slf4j-api:2.0.4=testCompileClasspath,testRuntimeClasspath +org.slf4j:slf4j-simple:2.0.0=spotbugsSlf4j +org.spockframework:spock-core:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.spockframework:spock-junit4:2.2-groovy-3.0=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath,testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-autoconfigure:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-autoconfigure:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-json:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-json:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-logging:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-logging:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-security:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-security:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-test:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-test:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-tomcat:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-tomcat:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter-web:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter-web:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-starter:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-starter:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-test-autoconfigure:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-test-autoconfigure:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot-test:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot-test:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.boot:spring-boot:3.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.boot:spring-boot:3.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.security:spring-security-config:6.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.security:spring-security-config:6.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.security:spring-security-core:6.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.security:spring-security-core:6.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.security:spring-security-crypto:6.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.security:spring-security-crypto:6.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework.security:spring-security-web:6.0.0=testCompileClasspath,testRuntimeClasspath +org.springframework.security:spring-security-web:6.3.3=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-aop:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-aop:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-beans:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-beans:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-context:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-context:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-core:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-core:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-expression:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-expression:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-jcl:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-jcl:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-test:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-test:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-web:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-web:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.springframework:spring-webmvc:6.0.2=testCompileClasspath,testRuntimeClasspath +org.springframework:spring-webmvc:6.1.12=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.testng:testng:7.5=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.webjars:jquery:3.5.1=latestDepTestRuntimeClasspath,testRuntimeClasspath +org.xmlresolver:xmlresolver:4.4.3=spotbugs +org.xmlunit:xmlunit-core:2.9.0=testCompileClasspath,testRuntimeClasspath +org.xmlunit:xmlunit-core:2.9.1=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +org.yaml:snakeyaml:1.33=testCompileClasspath,testRuntimeClasspath +org.yaml:snakeyaml:2.2=latestDepTestCompileClasspath,latestDepTestRuntimeClasspath +xml-apis:xml-apis:1.4.01=spotbugs +empty=main_java17AnnotationProcessor,spotbugsPlugins diff --git a/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/AppConfig.groovy b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/AppConfig.groovy new file mode 100644 index 00000000000..c33b48693a4 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/AppConfig.groovy @@ -0,0 +1,11 @@ +package datadog.trace.instrumentation.springsecurity6 + +import org.springframework.boot.autoconfigure.SpringBootApplication +import org.springframework.boot.autoconfigure.web.servlet.error.ErrorMvcAutoConfiguration +import org.springframework.web.servlet.config.annotation.WebMvcConfigurer + +// Component scan defeats the purpose of configuring with specific classes +@SpringBootApplication(exclude = [ErrorMvcAutoConfiguration]) +class AppConfig implements WebMvcConfigurer { + +} diff --git a/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/SecurityConfig.groovy b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/SecurityConfig.groovy new file mode 100644 index 00000000000..623698699b7 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/SecurityConfig.groovy @@ -0,0 +1,58 @@ +package datadog.trace.instrumentation.springsecurity6 + +import custom.CustomAuthenticationFilter +import custom.CustomAuthenticationProvider +import org.springframework.context.annotation.Bean +import org.springframework.context.annotation.Configuration +import org.springframework.security.authentication.AuthenticationManager +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.configurers.AbstractHttpConfigurer +import org.springframework.security.core.userdetails.UserDetails +import org.springframework.security.provisioning.InMemoryUserDetailsManager +import org.springframework.security.provisioning.UserDetailsManager +import org.springframework.security.web.SecurityFilterChain +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter + +@Configuration +@EnableWebSecurity +class SecurityConfig { + + @Bean + SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + http.apply(CustomDsl.customDsl()) + http + .csrf().disable() + .formLogin((form) -> form.loginPage("/login").permitAll()) + .authorizeHttpRequests() + .requestMatchers("/", "/success", "/register", "/login", "/custom").permitAll() + .anyRequest().authenticated() + return http.build() + } + + @Bean + UserDetailsManager userDetailsService() { + return new InMemoryUserDetailsManager() { + @Override + void createUser(UserDetails user) { + if (user.username == 'cant_create_me') { + throw new IllegalArgumentException('cannot create user') + } + super.createUser(user) + } + } + } + + static class CustomDsl extends AbstractHttpConfigurer { + @Override + void configure(HttpSecurity http) throws Exception { + AuthenticationManager authenticationManager = http.getSharedObject(AuthenticationManager) + http.authenticationProvider(new CustomAuthenticationProvider()) + http.addFilterBefore(new CustomAuthenticationFilter(authenticationManager), UsernamePasswordAuthenticationFilter) + } + + static CustomDsl customDsl() { + return new CustomDsl() + } + } +} diff --git a/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/SpringBootBasedTest.groovy b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/SpringBootBasedTest.groovy new file mode 100644 index 00000000000..0dca21ff574 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/SpringBootBasedTest.groovy @@ -0,0 +1,291 @@ +package datadog.trace.instrumentation.springsecurity6 + +import ch.qos.logback.classic.Logger +import ch.qos.logback.core.Appender +import com.datadog.appsec.AppSecHttpServerTest +import datadog.trace.agent.test.base.HttpServer +import datadog.trace.api.config.AppSecConfig +import datadog.trace.core.DDSpan +import datadog.trace.instrumentation.springsecurity5.SpringSecurityUserEventDecorator +import okhttp3.FormBody +import okhttp3.HttpUrl +import okhttp3.Request +import okhttp3.RequestBody +import org.springframework.boot.SpringApplication +import org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext +import org.springframework.context.ConfigurableApplicationContext +import spock.lang.Shared + +import static datadog.trace.agent.test.utils.OkHttpUtils.clientBuilder +import static datadog.trace.agent.test.utils.OkHttpUtils.cookieJar +import static datadog.trace.agent.test.utils.TraceUtils.runUnderTrace +import static datadog.trace.instrumentation.springsecurity6.TestEndpoint.CUSTOM +import static datadog.trace.instrumentation.springsecurity6.TestEndpoint.LOGIN +import static datadog.trace.instrumentation.springsecurity6.TestEndpoint.NOT_FOUND +import static datadog.trace.instrumentation.springsecurity6.TestEndpoint.REGISTER +import static datadog.trace.instrumentation.springsecurity6.TestEndpoint.SUCCESS +import static datadog.trace.instrumentation.springsecurity6.TestEndpoint.UNKNOWN + +class SpringBootBasedTest extends AppSecHttpServerTest { + + @Shared + def context + + SpringApplication application() { + return new SpringApplication(AppConfig, UserController, SecurityConfig) + } + + class SpringBootServer implements HttpServer { + def port = 0 + final app = application() + + @Override + void start() { + app.setDefaultProperties(["server.port": 0, "server.context-path": "/"]) + context = app.run() + port = (context as ServletWebServerApplicationContext).webServer.port + assert port > 0 + } + + @Override + void stop() { + context.close() + } + + @Override + URI address() { + return new URI("http://localhost:$port/") + } + + @Override + String toString() { + return this.class.name + } + } + + @Override + HttpServer server() { + return new SpringBootServer() + } + + + @Override + int version() { + return 0 + } + + @Override + String service() { + return null + } + + @Override + String operation() { + return null + } + + @Override + protected void configurePreAgent() { + super.configurePreAgent() + injectSysConfig(AppSecConfig.APPSEC_AUTO_USER_INSTRUMENTATION_MODE, 'identification') + } + + Request.Builder request(TestEndpoint uri, String method, RequestBody body) { + def url = HttpUrl.get(uri.resolve(address)).newBuilder() + .encodedQuery(uri.rawQuery) + .fragment(uri.fragment) + .build() + return new Request.Builder() + .url(url) + //.addHeader('user-agent', 'Arachni/v1') + .method(method, body) + } + + static T controller(TestEndpoint endpoint, Closure closure) { + if (endpoint == NOT_FOUND || endpoint == UNKNOWN) { + return closure() + } + return runUnderTrace("controller", closure) + } + + + def "test signup event"() { + setup: + RequestBody formBody = new FormBody.Builder() + .add("username", "admin") + .add("password", "admin") + .build() + + def request = request(REGISTER, "POST", formBody).build() + + when: + def response = client.newCall(request).execute() + TEST_WRITER.waitForTraces(1) + DDSpan span = TEST_WRITER.flatten().first() + + then: + response.code() == REGISTER.status + response.body().string() == REGISTER.body + !span.getTags().isEmpty() + span.getTag("appsec.events.users.signup.track") == true + span.getTag("_dd.appsec.events.users.signup.auto.mode") == 'identification' + span.getTag("usr.id") == 'admin' + span.getTag("appsec.events.users.signup")['enabled'] == 'true' + span.getTag("appsec.events.users.signup")['authorities'] == 'ROLE_USER' + } + + + def "test failed login with non existing user"() { + setup: + RequestBody formBody = new FormBody.Builder() + .add("username", "not_existing_user") + .add("password", "some_password") + .build() + + def request = request(LOGIN, "POST", formBody).build() + + when: + def response = client.newCall(request).execute() + TEST_WRITER.waitForTraces(1) + DDSpan span = TEST_WRITER.flatten().first() + + then: + response.code() == LOGIN.status + response.body().string() == LOGIN.body + !span.getTags().isEmpty() + span.getTag("appsec.events.users.login.failure.track") == true + span.getTag("_dd.appsec.events.users.login.failure.auto.mode") == 'identification' + span.getTag("appsec.events.users.login.failure.usr.exists") == false + span.getTag("appsec.events.users.login.failure.usr.id") == 'not_existing_user' + } + + + def "test failed login with existing user but wrong password"() { + setup: + RequestBody formBody = new FormBody.Builder() + .add("username", "admin") + .add("password", "wrong_password").build() + + def request = request(LOGIN, "POST", formBody).build() + + when: + def response = client.newCall(request).execute() + TEST_WRITER.waitForTraces(1) + DDSpan span = TEST_WRITER.flatten().first() + + then: + response.code() == LOGIN.status + response.body().string() == LOGIN.body + !span.getTags().isEmpty() + span.getTag("appsec.events.users.login.failure.track") == true + span.getTag("_dd.appsec.events.users.login.failure.auto.mode") == 'identification' + // TODO: Ideally should be `false` but we have no reliable method to detect it it is just absent. See APPSEC-12765. + span.getTag("appsec.events.users.login.failure.usr.exists") == null + span.getTag("appsec.events.users.login.failure.usr.id") == 'admin' + } + + + def "test success login"() { + setup: + RequestBody formBody = new FormBody.Builder() + .add("username", "admin") + .add("password", "admin") + .build() + + def request = request(LOGIN, "POST", formBody).build() + + when: + def response = client.newCall(request).execute() + TEST_WRITER.waitForTraces(1) + DDSpan span = TEST_WRITER.flatten().first() + + then: + response.code() == LOGIN.status + response.body().string() == LOGIN.body + !span.getTags().isEmpty() + span.getTag("appsec.events.users.login.success.track") == true + span.getTag("_dd.appsec.events.users.login.success.auto.mode") == 'identification' + span.getTag("usr.id") == 'admin' + span.getTag("appsec.events.users.login.success")['credentialsNonExpired'] == 'true' + span.getTag("appsec.events.users.login.success")['accountNonExpired'] == 'true' + span.getTag("appsec.events.users.login.success")['enabled'] == 'true' + span.getTag("appsec.events.users.login.success")['authorities'] == 'ROLE_USER' + span.getTag("appsec.events.users.login.success")['accountNonLocked'] == 'true' + } + + void 'test failed signup'() { + setup: + final formBody = new FormBody.Builder() + .add('username', 'cant_create_me') + .add('password', 'cant_create_me') + .build() + + final request = request(REGISTER, 'POST', formBody).build() + + when: + final response = client.newCall(request).execute() + TEST_WRITER.waitForTraces(1) + final span = TEST_WRITER.flatten().first() as DDSpan + + then: + response.code() == 500 + span.getTags().findAll { it.key.startsWith('appsec.events.users.signup') }.isEmpty() + } + + void 'test skipped authentication'() { + setup: + final appender = Mock(Appender) + final logger = SpringSecurityUserEventDecorator.LOGGER as Logger + logger.addAppender(appender) + + and: + final requestCount = 3 + final request = request(CUSTOM, "GET", null).addHeader('X-Custom-User', 'batman').build() + + when: + final response = (1..requestCount).collect { client.newCall(request).execute() }.first() + TEST_WRITER.waitForTraces(3) + final span = TEST_WRITER.flatten().first() as DDSpan + logger.detachAppender(appender) // cant add cleanup + + then: + response.code() == CUSTOM.status + span.context().resourceName.contains(CUSTOM.path) + span.getTags().findAll { key, value -> key.startsWith('appsec.events.users.login')}.isEmpty() + // single call to the appender + 1 * appender.doAppend(_) >> { + assert it[0].toString().contains('Skipped authentication, auth=org.springframework.security.authentication.AbstractAuthenticationToken') + } + 0 * appender._ + } + + void 'test user event'() { + setup: + def client = clientBuilder().cookieJar(cookieJar()).followRedirects(false).build() + def formBody = new FormBody.Builder() + .add("username", "admin") + .add("password", "admin") + .build() + + def loginRequest = request(LOGIN, "POST", formBody).build() + def loginResponse = client.newCall(loginRequest).execute() + assert loginResponse.code() == LOGIN.status + assert loginResponse.body().string() == LOGIN.body + TEST_WRITER.waitForTraces(1) + TEST_WRITER.start() // clear all traces + + when: + def request = request(SUCCESS, "GET", null).build() + def response = client.newCall(request).execute() + TEST_WRITER.waitForTraces(1) + def span = TEST_WRITER.flatten().first() as DDSpan + + then: + response.code() == SUCCESS.status + response.body().string() == SUCCESS.body + span.getResourceName().toString() == 'GET /success' + !span.getTags().isEmpty() + span.getTag("usr.id") == 'admin' + span.getTag("_dd.appsec.user.collection_mode") == 'ident' + } +} diff --git a/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/TestEndpoint.groovy b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/TestEndpoint.groovy new file mode 100644 index 00000000000..ab0c1528b26 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/TestEndpoint.groovy @@ -0,0 +1,50 @@ +package datadog.trace.instrumentation.springsecurity6 + +enum TestEndpoint { + LOGIN("login", 302, ""), + REGISTER("register", 200, ""), + NOT_FOUND("not-found", 404, "not found"), + UNKNOWN("", 451, null), // This needs to have a valid status code + CUSTOM("custom", 302, ""), + SUCCESS("success", 200, ""), + + private final String path + private final String rawPath + final String query + final String rawQuery + final String fragment + final int status + final String body + + TestEndpoint(String uri, int status, String body) { + def uriObj = URI.create(uri) + this.path = uriObj.path + this.rawPath = uriObj.rawPath + this.query = uriObj.query + this.rawQuery = uriObj.rawQuery + this.fragment = uriObj.fragment + this.status = status + this.body = body + } + + String getPath() { + return "/$path" + } + + String relativePath() { + return path + } + + String getRawPath() { + return "/$rawPath" + } + + String relativeRawPath() { + return rawPath + } + + URI resolve(URI address) { + // must be relative path to allow for servlet context + return address.resolve(relativeRawPath()) + } +} diff --git a/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/UserController.groovy b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/UserController.groovy new file mode 100644 index 00000000000..03b29f7c271 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/src/test/groovy/datadog/trace/instrumentation/springsecurity6/UserController.groovy @@ -0,0 +1,45 @@ +package datadog.trace.instrumentation.springsecurity6 + + +import org.springframework.security.core.userdetails.User +import org.springframework.security.provisioning.UserDetailsManager +import org.springframework.stereotype.Controller +import org.springframework.ui.Model +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.ResponseBody + +import static datadog.trace.instrumentation.springsecurity6.TestEndpoint.REGISTER +import static datadog.trace.instrumentation.springsecurity6.TestEndpoint.SUCCESS + +@Controller +class UserController { + + private final UserDetailsManager userDetailsManager + + UserController(UserDetailsManager userDetailsManager) { + this.userDetailsManager = userDetailsManager + } + + @RequestMapping("/success") + @ResponseBody + String success() { + SpringBootBasedTest.controller(SUCCESS) { + SUCCESS.body + } + } + + @PostMapping("/register") + @ResponseBody + void register( + @RequestParam("username") String username, + @RequestParam("password") String password, + Model model) { + SpringBootBasedTest.controller(REGISTER) { + userDetailsManager.createUser( + User.withUsername(username).password("{noop}" + password).roles("USER").build()) + model.addAttribute("username", username) + } + } +} diff --git a/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationFilter.java b/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationFilter.java new file mode 100644 index 00000000000..b3ec62a572b --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationFilter.java @@ -0,0 +1,33 @@ +package custom; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import java.io.IOException; +import org.springframework.security.authentication.AuthenticationManager; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter; + +public class CustomAuthenticationFilter extends AbstractAuthenticationProcessingFilter { + + private static final String HEADER_NAME = "X-Custom-User"; + + private final AuthenticationManager authenticationManager; + + public CustomAuthenticationFilter(final AuthenticationManager authenticationManager) { + super("/custom"); + this.authenticationManager = authenticationManager; + } + + @Override + public Authentication attemptAuthentication( + HttpServletRequest request, HttpServletResponse response) + throws AuthenticationException, IOException, ServletException { + final String user = request.getHeader(HEADER_NAME); + if (user == null) { + return null; + } + return authenticationManager.authenticate(new CustomAuthenticationToken(user)); + } +} diff --git a/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationProvider.java b/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationProvider.java new file mode 100644 index 00000000000..ac9b8706ab9 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationProvider.java @@ -0,0 +1,18 @@ +package custom; + +import org.springframework.security.authentication.AuthenticationProvider; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.AuthenticationException; + +public class CustomAuthenticationProvider implements AuthenticationProvider { + + @Override + public Authentication authenticate(Authentication authentication) throws AuthenticationException { + return authentication; + } + + @Override + public boolean supports(Class authentication) { + return CustomAuthenticationToken.class.isAssignableFrom(authentication); + } +} diff --git a/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationToken.java b/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationToken.java new file mode 100644 index 00000000000..b85fdc4ad99 --- /dev/null +++ b/dd-java-agent/instrumentation/spring-security-6/src/test/java/custom/CustomAuthenticationToken.java @@ -0,0 +1,24 @@ +package custom; + +import java.util.Collections; +import org.springframework.security.authentication.AbstractAuthenticationToken; + +public class CustomAuthenticationToken extends AbstractAuthenticationToken { + + private final String user; + + public CustomAuthenticationToken(String user) { + super(Collections.emptyList()); + this.user = user; + } + + @Override + public Object getCredentials() { + return user; + } + + @Override + public Object getPrincipal() { + return user; + } +} diff --git a/internal-api/src/main/java/datadog/trace/api/appsec/AppSecEventTracker.java b/internal-api/src/main/java/datadog/trace/api/appsec/AppSecEventTracker.java index 204c53a3736..c4e84ae317e 100644 --- a/internal-api/src/main/java/datadog/trace/api/appsec/AppSecEventTracker.java +++ b/internal-api/src/main/java/datadog/trace/api/appsec/AppSecEventTracker.java @@ -47,6 +47,8 @@ public abstract void onLoginSuccessEvent( public abstract void onLoginFailureEvent( UserIdCollectionMode mode, String userId, Boolean exists, Map metadata); + public abstract void onUserEvent(UserIdCollectionMode mode, String userId); + public abstract void onCustomEvent( UserIdCollectionMode mode, String eventName, Map metadata); } diff --git a/settings.gradle b/settings.gradle index d332a3df27d..130d0035043 100644 --- a/settings.gradle +++ b/settings.gradle @@ -433,6 +433,7 @@ include ':dd-java-agent:instrumentation:spring-messaging-4' include ':dd-java-agent:instrumentation:spring-rabbit' include ':dd-java-agent:instrumentation:spring-scheduling-3.1' include ':dd-java-agent:instrumentation:spring-security-5' +include ':dd-java-agent:instrumentation:spring-security-6' include ':dd-java-agent:instrumentation:spring-webflux-5' include ':dd-java-agent:instrumentation:spring-webflux-6' include ':dd-java-agent:instrumentation:spring-webmvc-3.1'