javax.mail doesn't seem to be truly optional

Issue #291 resolved
Josh Cummings created an issue

In 7.1, if an application does the following:

HTTPResponse response = new HTTPResponse(200);

Then, an exception is thrown:

Caused by: java.lang.ClassNotFoundException: javax.mail.internet.ParseException
    at java.net.URLClassLoader.findClass (URLClassLoader.java:382)
    at java.lang.ClassLoader.loadClass (ClassLoader.java:418)
    at java.lang.ClassLoader.loadClass (ClassLoader.java:351)

However, HTTPResponse is not deprecated. It appears that some effort was made to keep the classloader from trying to load javax.mail.internet.ParseException; however, it may not suffice.

When logging the classloader with -verbose:class, I get:

...
[Loaded com.nimbusds.oauth2.sdk.http.HTTPMessage from file:/home/jzheaux/.m2/repository/com/nimbusds/oauth2-oidc-sdk/7.1/oauth2-oidc-sdk-7.1.jar]
[Loaded com.nimbusds.oauth2.sdk.http.HTTPResponse from file:/home/jzheaux/.m2/repository/com/nimbusds/oauth2-oidc-sdk/7.1/oauth2-oidc-sdk-7.1.jar]
[Loaded javax.mail.MessagingException from file:/home/jzheaux/.m2/repository/javax/mail/javax.mail-api/1.6.1/javax.mail-api-1.6.1.jar]
[Loaded javax.mail.internet.ParseException from file:/home/jzheaux/.m2/repository/javax/mail/javax.mail-api/1.6.1/javax.mail-api-1.6.1.jar]
[Loaded java.text.ParseException from /home/jzheaux/.sdkman/candidates/java/8.0.232-zulu/jre/lib/rt.jar]
[Loaded com.nimbusds.oauth2.sdk.GeneralException from file:/home/jzheaux/.m2/repository/com/nimbusds/oauth2-oidc-sdk/7.1/oauth2-oidc-sdk-7.1.jar]
[Loaded com.nimbusds.oauth2.sdk.ParseException from file:/home/jzheaux/.m2/repository/com/nimbusds/oauth2-oidc-sdk/7.1/oauth2-oidc-sdk-7.1.jar]
...

The Java version I’m using is

openjdk version "1.8.0_232"
OpenJDK Runtime Environment (Zulu 8.42.0.21-CA-linux64) (build 1.8.0_232-b18)
OpenJDK 64-Bit Server VM (Zulu 8.42.0.21-CA-linux64) (build 25.232-b18, mixed mode)

I’ve posted a sample project with some reproducing instructions. I believe HTTPRequest may have the same issue.

My specific use case is to query a token introspection endpoint, which requires me to work with an HTTPResponse instance, as far as I can tell.

Is there a better way to address my use case than adding the javax.mail dependency? Or, is there a way to make javax.mail truly optional? If not, it may alleviate some confusion to add the dependency back in since it is still required for some basic use cases.

Comments (13)

  1. Yavor Vasilev
    • changed status to open

    Ouch, this doesn't look good. We wanted to get rid of javfax.mail entirely, unless you're using deprecated calls.

  2. Yavor Vasilev

    The constructor is this:

    public HTTPResponse(final int statusCode) {
    
            this.statusCode = statusCode;
    }
    

    There is use of javax.mail in a few methods in the parent HTTPMessage class, but they don’t get called during construction.

    I need to figure out why the class loads tries to load what it does.

  3. Yavor Vasilev

    IN the meantime you can add javax.mail to your project which will sort out the loading error:

            <dependency>
                <groupId>com.sun.mail</groupId>
                <artifactId>javax.mail</artifactId>
                <version>1.6.1</version>
            </dependency>
    

  4. Josh Cummings reporter

    Just as an extra datapoint, this also appears to happen with:

    JSONObject object = JSONObjectUtils.parse("{ 'some' : 'json' }");
    

    It gives the exception:

    Caused by: java.lang.ClassNotFoundException: javax.mail.internet.AddressException
        at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
    

  5. Josh Cummings reporter

    Okay, thanks for looking into it.

    but they don’t get called during construction.

    I’m not a classloader guy, but I think it’s because the compiler will translate catch clauses to an exception table. You can see the exception table that is generated for HTTPMessage#getContentType by doing a javap -c HTTPMessage.

    IN the meantime you can add javax.mail to your project which will sort out the loading error:

    Since we are also a dependency that others use (Spring Security), adding the javax.mail dependency probably won’t resolve the problem for us since folks will see it in Spring Security vulnerability reports.

    That said, I was able to get past the errors by modifying the Nimbus classes that catch Java Mail exceptions. Let me know if that’s something you’d consider merging.

    Speaking from some experience with a similar issue, it may not address all classloader gotchas, but it should address my issue.

  6. Yavor Vasilev

    Oh that’s great that you found a solution. I was reading up last night and couldn’t find a detailed spec of what and how typically gets loaded by default, other than “loading being demand driven”. Perhaps this various from one JVM version / impl to another.

    If you’re confident the solution will work for you we’ll merge it.

    I’ve been working on implementing federation, a new major addition to the SDK, and once it’s done we’ll probably make another major release (8.0) and if the optional javax.mail is still causing trouble we’ll remove it entirely then.

    There are no sec issues with the classes used in the SDK - for representing email addresses and Content-type headers.

  7. Josh Cummings reporter

    So, doing a bit more research, especially related to the issue I referenced earlier, there's still a risk that anything that calls HTTPResponse or JSONObjectUtils could cause javax.mail.internet.InternetAddress to be loaded. My understanding (now) is that if a class uses javax.mail in any method body or signature, even if the method is not invoked, then it can cause classloader issue. To make sure, I further correlated this finding with Rob Winch from the Spring Security team.

    While Spring Security can pretty easily pivot away from using HTTPResponse, it’s not likely that it can avoid JSONObjectUtils.

    Sadly, I think that means that removing the references to Java Mail’s exceptions will not be sufficient for Spring Security to be able to take the upgrade. Likely, we won’t upgrade until javax.mail is truly optional, meaning that javax.mail is not referred to by core classes like HTTPResponse and JSONObjectUtils.

    Going back to my earlier comment then, can Nimbus add the dependency back in? That is, until 8.0 when those methods can be removed altogether?

  8. Henri Mikkonen

    The dependency to javax.mail is quite irritating from some of my projects' perspective too.

    V8.0 should appear in March or April.

    What’s the current status regarding the schedule?

  9. Yavor Vasilev

    I’m still working on the v8.0. The main task there is to add support for OIDC federation which has proven more complex than anticipated and we had to postpone release to customers once already.

    I believe the April deadline can still be held.

  10. Log in to comment