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.
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:
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.
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:
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
We will be asked to restart SonarQube to complete the plugin installation. Once this is done, we notice that new quality profiles are available:
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.
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:
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
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
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
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:
When going to the project’s overview page, we see the following:
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 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.
Quality Profiles section, we create a new quality profile:
We then take advantage of the inheritance between quality profiles by changing the parent of our newly created profile:
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:
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.
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.