NullPointerException in UserEnumerationCheck when throwing UsernameNotFoundException from lambda

Hi there,

first of all I hope this is the right place to report issues, I tried to log into the Jira (via Atlassian ID) to create an issue but it seems to be locked to maintainer only or at least activated people.

I found that there is a NullPointerException during scannig. From my analysis it seems, that the UserEnumerationCheck does not like to find a UsernameNotFoundException while inside a lambda. When it finds that exception it checks if it is thrown inside the loadByUsername of UserDetailsService. But as in my case it is a lamda (representing exactly this method) it fails with the NullPointerException as stack.peekFirst for that case returns null and the MethodMatchers does not check for null.

Below you find details about our environment as well as the affected file and the part of the log.

SonarQube Server

Community Build
v25.2.0.102705
Standard Experience
Deployed via Docker

Scanner

Maven Plugin sonar:5.0.0.4389
Java 21.0.6 Eclipse Adoptium (64-bit)
Linux 5.4.0-162-generic (amd64) (docker JDK 21 temurin image)

Affected File

package redacted.server.core.security;

import org.springframework.context.annotation.Profile;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

@Profile("development")
@Service("customAuthenticationProvider")
public class CustomAuthenticationProvider extends DaoAuthenticationProvider {

	public CustomAuthenticationProvider(UserDetailsMapper userDetailsMapper) {

		BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
		setPasswordEncoder(passwordEncoder);

		UserDetailsService userDetailsService =
				userDetailsMapper.asUserDetailsService();
		String adminPW = passwordEncoder.encode("admin");

		setUserDetailsService(username -> {
			if (username.equals("admin")) {
				UserDetailsImpl userDetails =
						(UserDetailsImpl) userDetailsService
							.loadUserByUsername(username);
				return new UserDetailsImpl(userDetails, adminPW);
			}

			throw new UsernameNotFoundException("no valid user found");
		});
	}
}

Logs

[INFO] ------------- Run sensors on module my-webapp
[INFO] Sensor JavaSensor [java]
[INFO] Configured Java source version (sonar.java.source): 21, preview features enabled (sonar.java.enablePreview): false
[INFO] Server-side caching is enabled. The Java analyzer will not try to leverage data from a previous analysis.
[INFO] Using ECJ batch to parse 265 Main java source files with batch size 500 KB.
[INFO] Starting batch processing.
[INFO] The Java analyzer cannot skip unchanged files in this context. A full analysis is performed for all files.
[INFO] 37% analyzed
[ERROR] Unable to run check class org.sonar.java.checks.security.UserEnumerationCheck - S5804 on file 'my-webapp/src/main/java/redacted/server/core/security/CustomAuthenticationProvider.java', To help improve the SonarSource Java Analyzer, please report this problem to SonarSource: see https://community.sonarsource.com/
java.lang.NullPointerException: Cannot invoke "org.sonar.plugins.java.api.tree.MethodTree.symbol()" because "methodTree" is null
	at org.sonar.java.matcher.MethodMatchersBuilder.matches(MethodMatchersBuilder.java:192)
	at org.sonar.java.checks.security.UserEnumerationCheck.isInsideLoadUserByUserName(UserEnumerationCheck.java:136)
	at org.sonar.java.checks.security.UserEnumerationCheck.visitNode(UserEnumerationCheck.java:85)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.lambda$visit$6(VisitorsBridge.java:464)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.lambda$forEach$9(VisitorsBridge.java:480)
	at org.sonar.java.model.VisitorsBridge.runScanner(VisitorsBridge.java:277)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.forEach(VisitorsBridge.java:480)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:466)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visitChildren(VisitorsBridge.java:450)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.visit(VisitorsBridge.java:470)
	at org.sonar.java.model.VisitorsBridge$IssuableSubscriptionVisitorsRunner.scanFile(VisitorsBridge.java:428)
	at org.sonar.java.model.VisitorsBridge.lambda$runScanner$1(VisitorsBridge.java:272)
	at org.sonar.java.model.VisitorsBridge.runScanner(VisitorsBridge.java:277)
	at org.sonar.java.model.VisitorsBridge.runScanner(VisitorsBridge.java:272)
	at org.sonar.java.model.VisitorsBridge.visitFile(VisitorsBridge.java:255)
	at org.sonar.java.ast.JavaAstScanner.simpleScan(JavaAstScanner.java:131)
	at org.sonar.java.JavaFrontend.scanAsBatchCallback(JavaFrontend.java:243)
	at org.sonar.java.JavaFrontend.lambda$scanBatch$0(JavaFrontend.java:234)
	at org.sonar.java.model.JParserConfig$Batch$1.acceptAST(JParserConfig.java:187)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:1197)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver.resolve(CompilationUnitResolver.java:786)
	at org.eclipse.jdt.core.dom.CompilationUnitResolver$ECJCompilationUnitResolver.resolve(CompilationUnitResolver.java:92)
	at org.eclipse.jdt.core.dom.ASTParser.createASTs(ASTParser.java:1071)
	at org.sonar.java.model.JParserConfig$Batch.parse(JParserConfig.java:173)
	at org.sonar.java.JavaFrontend.scanBatch(JavaFrontend.java:234)
	at org.sonar.java.JavaFrontend.scanInBatches(JavaFrontend.java:223)
	at org.sonar.java.JavaFrontend.scanAsBatch(JavaFrontend.java:190)
	at org.sonar.java.JavaFrontend.scan(JavaFrontend.java:165)
	at org.sonar.plugins.java.JavaSensor.execute(JavaSensor.java:109)
	at org.sonar.scanner.sensor.AbstractSensorWrapper.analyse(AbstractSensorWrapper.java:64)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:88)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.lambda$execute$1(ModuleSensorsExecutor.java:61)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.withModuleStrategy(ModuleSensorsExecutor.java:79)
	at org.sonar.scanner.sensor.ModuleSensorsExecutor.execute(ModuleSensorsExecutor.java:61)
	at org.sonar.scanner.scan.SpringModuleScanContainer.doAfterStart(SpringModuleScanContainer.java:82)
	at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:226)
	at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:205)
	at org.sonar.scanner.scan.SpringProjectScanContainer.scan(SpringProjectScanContainer.java:201)
	at org.sonar.scanner.scan.SpringProjectScanContainer.scanRecursively(SpringProjectScanContainer.java:197)
	at org.sonar.scanner.scan.SpringProjectScanContainer.scanRecursively(SpringProjectScanContainer.java:194)
	at org.sonar.scanner.scan.SpringProjectScanContainer.doAfterStart(SpringProjectScanContainer.java:170)
	at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:226)
	at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:205)
	at org.sonar.scanner.bootstrap.SpringScannerContainer.doAfterStart(SpringScannerContainer.java:350)
	at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:226)
	at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:205)
	at org.sonar.scanner.bootstrap.SpringGlobalContainer.doAfterStart(SpringGlobalContainer.java:142)
	at org.sonar.core.platform.SpringComponentContainer.startComponents(SpringComponentContainer.java:226)
	at org.sonar.core.platform.SpringComponentContainer.execute(SpringComponentContainer.java:205)
	at org.sonar.scanner.bootstrap.ScannerMain.runScannerEngine(ScannerMain.java:151)
	at org.sonar.scanner.bootstrap.ScannerMain.run(ScannerMain.java:66)
	at org.sonar.scanner.bootstrap.ScannerMain.main(ScannerMain.java:52)

[INFO] 100% analyzed
[INFO] Batch processing: Done.

Hi @Dodge,

Thanks for reporting this issue, and yes, you are reporting in the right place.

I will have a look into the issue and come back to you.

Cheers,

Dorian

Hi @Dodge,
I looked into the issue and could reproduce it. I created a ticket to track the issue.

Cheers,

Dorian

Hey Dorian_Burihabwa

thank you for your quick response and creating that ticket.

I did not thought about the fact, that it might be a problem with beein in the constructor instead of related to the fact that it was in the lambda. :slight_smile: