Using SonarQube to Analyze a Java Project

For the past weeks, I have tried to leverage SonarQube in order to do static analysis of the James source code. This article reports and describes some of the things I did to eventually spot a few security issues in James.

What Is SonarQube?

SonarQube is an open-source platform for continuous inspection of code quality. Using static code analysis, it tries to detect bugs, code smells and security vulnerabilities. SonarQube supports many languages through built-in rulesets and can also be extended with various plugins.

In this article, we are particularly interested in security issues. Many static analysis tools exist for the Java language, including free and open-source ones. Some advantages of SonarQube are the following:

  • It is actively developed and well integrated. Many plugins are available to use it as part of continuous integration pipelines, including for Maven, Jenkins and GitHub.
  • Its built-in rulesets can be extended with plugins that are more security-oriented. For instance, we will use the FindBugs plugin to take advantage of FindBugs rules.
  • It can also report things such as duplicated code, code coverage or coding standards.

Installation

To ease things up, here is the Docker Compose YAML file we are going to use:

Below is the corresponding start.sh script that serves as an entry point. It is mainly responsible for creating a new user whose credentials were defined above and with high privileges. We also add the JAR file for the OWASP Dependency Check that we will introduce later.

One should note that we use an external MySQL database instead of the default built-in one. This is important for various reasons, including being able to migrate all the data through SonarQube upgrades. Moreover, here is the additional configuration snippet required to avoid errors later when Maven will be sending analysis reports to SonarQube:

As for the OWASP Dependency Check JAR file, you can download it here.

We can now use our web browser to log in to the SonarQube web interface on port 9000 and see the following page:

SonarQube startup page after login

As expected, the page is empty and we need to create and setup a new project. Before doing so, we can already take a look at the Administration section and start configuring our SonarQube instance. For instance, in the General Settings -> Security section, we can enable the Force user authentication option. We can also configure webhooks, setup the database cleaner or configure an email account to send notifications. In the System tab, we can for instance check the status of the underlying JVM, of the MySQL database or of the Compute and Search engines. In Administration -> Security, we can manage user permissions, user groups and create permission templates.

Setting Up a New Project

Our goal is to run a security-oriented analysis of the James source code. Before running an analysis, we need to setup a new project and assign it a quality profile. A quality profile is a collection of rules that will be applied during an analysis. There is a default one for each language. For instance, if we do not do any further configuration and directly analyze the James project, the built-in Java quality profile named Sonar way will be used.

The default “Sonar way” built-in Java quality profile

To create the new Apache James project, we go to the Projects -> Management section and create a new project. We can choose the name of the project as well as a project key, which needs to be unique. Then, a good practice would be for instance to create a new group with full permissions on this project. We first need to create the group from the general administration panel and then give it rights from the Apache James project administration tab. In our case, we created the james-team group for the Apache James project:

The james-team group has full permissions on the Apache James project

We then need to choose a different quality profile for the project. We are going to use the Findbugs Security Audit quality profile to benefit from the most security rules available. For that, we need to install the Findbugs plugin. We go to the Marketplace tab of the Administration section and search for findbugs. The first and only result is the good one and we can click on Install.

Let’s install the Findbugs plugin to gain a lot of new security-oriented rules

We will be asked to restart SonarQube to complete the plugin installation. Once this is done, we notice that new quality profiles are available:

New quality profiles are available thanks to the Findbugs plugin

We can check out these new quality profiles and see what rules they import and use. In SonarQube, rules are divided into three self-explaining categories: bugs, vulnerabilities and code smells. By default, some are active and some are not. This can of course be changed.

Back to the Apache James project section, we can now set the quality profile we want to use. As no analysis has been done yet, SonarQube does not know that we are dealing with a Java-only project and thus it is still possible to choose a different quality profile for each language. We obviously limit ourselves to Java and choose the Findbugs Security Audit profile.

The Findbugs Security Audit quality profile is set for the Java language

It is now time to run our first analysis of the Apache James project.

Running an Analysis

James uses Maven as its build automation tool. Maven works well with SonarQube thanks to its SonarQube Scanner plugin. We just need to add a few settings to Maven’s configuration and we will then be able to run a simple mvn command from the source repository of James. Beforehand, as authentication is required, we generate a security token. For this, we go to the My Account section of the user we want to use to run the analysis and we generate a new token:

A new token is generated and will be given to Maven when running the analysis

Analyzing a Maven project then simply consists of running a Maven goal sonar:sonar in the project source directory. We first need to add the following profile to our Maven configuration (usually in conf/settings.xml) or in the project’s pom.xml file:

You can see the security token we generated above. You may also wonder why we are not setting a project key. Actually, Maven automatically uses the following pattern for a project key: <groupId>:<artifactId>. We cannot do anything about it. If we chose to keep “our” key and set it in the above configuration file, Maven would complain and throw an error. If we used a different key, SonarQube would just create a new different project and we would not benefit from all the settings we have made thus far. Therefore, we must update the key of the project on the SonarQube web interface. In our case, we set it to org.apache.james:james-project.

We also exclude all test files from the analysis as well as some other source directories we do not care about.

Then, we run the following command to build James and let Maven directly cooperate with our SonarQube server to run the configured quality profile:

root@server:~/james-project# mvn clean install sonar:sonar -DskipTests

We also choose to skip the tests to gain time but note that as a consequence SonarQube will not produce any test related data, such as code coverage and test success statistics. Therefore, if you need such things, you should rather run the above command without the -DskipTests option.

It is worth noting that all the properties added to the XML configuration file above can also be provided as command-line options. This can be useful for instance when such a file is in a Git repository and you do not want to leak the login security token.

Once the build and analysis are completed, you should observe something similar to this in the SonarQube web interface:

Our Apache James project was correctly analyzed

When going to the project’s overview page, we see the following:

136 vulnerabilities were reported by SonarQube

We are presented with the number of reported bugs, vulnerabilities and code smells. The code coverage is also displayed but is zero as we did not run the tests. Statistics about code duplication are also showed. Finally, the evolution since the last analysis is presented so we can quickly see whether the situation has improved or not.

Let’s now go to the Issues tab. It is possible to use filters on many criteria such as severity, files or rules:

We focus on one particular class of reported issues about XML External Entity attacks

We can click on an issue to jump to the related source code. Then we can for instance decide to change the category of the issue, adapt its severity, confirm it or mark it as resolved, assign it to someone, write a comment, etc.

Obviously, many false positives will show up. With other quality profiles that include rules for bugs and code smells, you will probably decide that some do not matter to you. Consequently, you will need to disable certain rules. You may also want to mix rules from different quality profiles. The best way to achieve all of these actions is to create a custom quality profile.

Creating a Custom Quality Profile

Creating a custom quality profile is interesting because:

  • Default profiles cannot be edited, so we will not be able to customize it to our needs.
  • That lets us treat default profiles as a baseline against which we can track our own profile as we make changes to it.
  • Default profiles are typically updated with each new version of their associated plugin to add rules and sometimes adjust rules severities. These changes are automatically applied to existing copies of the profiles.

Note than the following will require us to have the Administer Quality Profiles global permission or to be a member of the sonar-administrators group, which is already the case for our user thanks to our initial Bash script.

In the Quality Profiles section, we create a new quality profile:

We create a new quality profile named test-james-security

We then take advantage of the inheritance between quality profiles by changing the parent of our newly created profile:

Our newly created profile will inherit from the Findbugs Security Audit profile we used for our first analysis

Do not forget to assign this new quality profile to your project so it will be used for the next analysis.

We can now enable or disable rules. For example, we can look for currently inactive Java rules included in the Findbugs Security Audit quality profile and that are classified as vulnerabilities with a Blocker severity:

We can browse inactive rules and activate some

It is also possible to back up our custom quality profile by downloading it as a file, allowing us to import it later in the same SonarQube instance or in another one. We can also compare different quality profiles, for instance if some day we want to get a summary of how our custom quality profiles have evolved and derived from their original parents.

Finally, note that rules can be flagged as deprecated. This merely acts as a warning and does not automatically disable active rules. Deprecations will appear with plugin updates and be propagated to our custom quality profiles since we used inheritance as showed above.

Conclusion

SonarQube is a relatively practical tool and comes with a nice user interface. It can almost work out of the box but one need to spend some time to configure it in order to really take advantage of it. This article was a quick introduction to walk people through a simple setup. There are many facets of SonarQube that we did not cover here. The documentation will help you find out more and we will probably publish another article dealing with more advanced uses of SonarQube (including the interfacing with the OWASP Dependency Check) and summarizing our results.