6

I recently upgraded one of my services to Spring Boot 2.1.5.RELEASE FROM 2.0.9.RELEASE. And I can't really go back, because I need some of the new features. The Spring Security Version pulled by Spring Boot is 5.1.5.RELEASE. Furthermore I'm using spring-security-jwt, version 1.0.10.RELEASE, and spring-security-oauth2', version 2.3.6.RELEASE.'

All unit and integration tests are fine and I was just about to release it when the "real world" test that uses the jar-file built by gradle blew up. When trying to obtain a token from '/oauth/token' I get the exception shown below.

The frustrating thing now is that the endpoint will work perfectly if I run it using gradle bootrun. But If I build the jar with gradle bootjar and then run it with java -jar service.jar the exception will show up.

Maybe someone already had this experience and knows what to do. I'm not sure which part of my code I could post to help investigating the issue and I'm not allowed to make the project public on GitHub.

ERROR  org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.handleException:169
Handling error: IllegalStateException, This object has not been built
java.lang.IllegalStateException: This object has not been built
    at org.springframework.security.config.annotation.AbstractSecurityBuilder.getObject(AbstractSecurityBuilder.java:55) ~[spring-security-config-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.authenticate(WebSecurityConfigurerAdapter.java:508) ~[spring-security-config-5.1.5.RELEASE.jar!/:5.1.5.RELEASE]
    at org.springframework.security.oauth2.provider.password.ResourceOwnerPasswordTokenGranter.getOAuth2Authentication(ResourceOwnerPasswordTokenGranter.java:71) ~[spring-security-oauth2-2.3.6.RELEASE.jar!/:?]
    at org.springframework.security.oauth2.provider.token.AbstractTokenGranter.getAccessToken(AbstractTokenGranter.java:72) ~[spring-security-oauth2-2.3.6.RELEASE.jar!/:?]
    at org.springframework.security.oauth2.provider.token.AbstractTokenGranter.grant(AbstractTokenGranter.java:67) ~[spring-security-oauth2-2.3.6.RELEASE.jar!/:?]
    at org.springframework.security.oauth2.provider.CompositeTokenGranter.grant(CompositeTokenGranter.java:38) ~[spring-security-oauth2-2.3.6.RELEASE.jar!/:?]
    at org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer$4.grant(AuthorizationServerEndpointsConfigurer.java:583) ~[spring-security-oauth2-2.3.6.RELEASE.jar!/:?]
    at org.springframework.security.oauth2.provider.endpoint.TokenEndpoint.postAccessToken(TokenEndpoint.java:132) ~[spring-security-oauth2-2.3.6.RELEASE.jar!/:?]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_211]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_211]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_211]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_211]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) [spring-webmvc-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) [spring-webmvc-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) [spring-webmvc-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:908) [spring-webmvc-5.1.7.RELEASE.jar!/:5.1.7.RELEASE]
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:665) [javax.servlet-api-4.0.1.jar!/:4.0.1]
    ...
    ...
    ...

UPDATE: I digged a little deeper. The "problematic" code resides in WebSecurityConfigurerAdapter. In the bootRun-case delegateBuilderin line 508 is a org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$DefaultPasswordEncoderAuthenticationManagerBuilder which has already been built and therefore getObjectsucceeds and delegate is not null anymore for future calls. In the bootJar-case the delegateBuilder is of the same class, but the internal building-flag is false. And that's why the exception is thrown.

500:    public Authentication authenticate(Authentication authentication)
501:            throws AuthenticationException {
502:        if (delegate != null) {
503:            return delegate.authenticate(authentication);
504:        }
505:
506:        synchronized (delegateMonitor) {
507:            if (delegate == null) {
508:                delegate = this.delegateBuilder.getObject();
509:                this.delegateBuilder = null;
510:            }
511:        }
512:
513:        return delegate.authenticate(authentication);
514:    }

UPDATE: The build file:

buildscript {
    ext {
        springBootVersion = '2.1.5.RELEASE'
    }

    repositories {
        jcenter()
        maven { url "http://repo.spring.io/snapshot" }
        maven { url "http://repo.spring.io/milestone" }
    }

    dependencies {
        classpath "org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}"
    }
}

apply plugin: "java"
apply plugin: "eclipse"
apply plugin: "org.springframework.boot"
apply plugin: "io.spring.dependency-management"

//Java version
sourceCompatibility = 1.8
targetCompatibility = 1.8 


defaultTasks "bootRun"


/* Configuration of the application package */

jar {
    baseName = "service"
    version =  "1.0.0"
}

bootJar {
    manifest {
        attributes("Manifest-Version": "1.0",
            "Specification-Title": "Example Service",
            "Specification-Version": "1.0",
            "Specification-Vendor": "Company",
            "Implementation-Title": "com.company.service",
            "Implementation-Version": "1.0.0",
            "Implementation-Vendor": "Company Inc.")
    }
}

repositories {
    jcenter()
    mavenCentral()
    maven { url "https://repo.spring.io/libs-release" }
    maven { url "http://repo.spring.io/snapshot" }
    maven { url "http://repo.spring.io/milestone" }
}

dependencies {
    implementation group:"org.springframework.boot", name:"spring-boot-starter-jersey"
    implementation group:"org.springframework.boot", name:"spring-boot-starter-tomcat"
    implementation group:"org.springframework.boot", name:"spring-boot-starter-log4j2"

    implementation group:"org.springframework.boot", name:"spring-boot-starter-actuator"

    implementation group:"org.springframework.boot", name:"spring-boot-devtools"

    implementation group:"org.apache.logging.log4j", name:"log4j-jul"

    implementation group:"javax.servlet", name:"javax.servlet-api"
    implementation group:"org.glassfish.jersey.containers", name:"jersey-container-servlet"
    implementation group:"org.glassfish.jersey.inject", name:"jersey-hk2"
    implementation group:"org.glassfish.jersey.ext", name:"jersey-spring4"

    implementation group:"org.springframework", name:"spring-context"
    implementation group:"org.springframework", name:"spring-web"
    implementation group:"org.springframework", name:"spring-aspects"

    implementation group:"org.springframework.security", name:"spring-security-core"
    implementation group:"org.springframework.security", name:"spring-security-web"
    implementation group:"org.springframework.security", name:"spring-security-config"
    implementation group:"org.springframework.security", name:"spring-security-jwt", version:"1.0.10.RELEASE"
    implementation group:"org.springframework.security.oauth", name:"spring-security-oauth2", version:"2.3.6.RELEASE"
    implementation group:"org.jasypt", name:"jasypt", version:"1.9.3"

    implementation group:"org.thymeleaf", name:"thymeleaf-spring5"

    implementation group:"org.springframework.data", name:"spring-data-jpa"
    implementation group:"org.hibernate", name:"hibernate-core"
    implementation group:"org.apache.tomcat", name:"tomcat-jdbc", version:"9.0.1"
    implementation group: "org.postgresql", name:"postgresql", version:"42.2.5"

    implementation group:"org.apache.commons", name:"commons-text", version:"1.6"
    implementation group:"commons-validator", name:"commons-validator", version:"1.6"

    testImplementation group:"org.springframework.boot", name:"spring-boot-starter-test"
    testImplementation group:"org.apache.httpcomponents", name:"httpclient"
}

configurations.all {
   exclude group:"org.springframework.boot", module: "spring-boot-starter-logging"
   exclude group:"ch.qos.logback", module:"logback-core"
   exclude group:"commons-logging", module:"commons-logging"
}

UPDATE:

Here is a repository that let's you reproduce the problem. The problem will go away if I remove EncryptionConverter from the project or just remove the @Autowired Encryptor. Of course this is not a solution since actually autowiring something into a Converterwas one of the main reasons for upgrading Spring Boot in the first place. Very interesting is also that the problem also will go away if I remove the class PasswordResetManagerImpl which is easy to de because it isn't used in the example project anyway. Exactly speaking it suffices to remove the injected PersistenceContextin that class. I guess that those to classes are in conflict somehow. But again, this is only a problem when starting the jar-file. Just running the project with bootRun? still works perfectly fine.

Fencer
  • 1,026
  • 11
  • 27
  • I'm not sure if my problem is related to https://stackoverflow.com/questions/43982952/o-s-s-o-provider-endpoint-tokenendpoint-handling-error-illegalstateexception. The symptom seems to be the same, but I'm not sure about the reason. – Fencer Jul 12 '19 at 09:40
  • Could you please add your `build.gradle` code? looks like you have packages clashed. – Jonathan JOhx Jul 18 '19 at 17:30
  • I'm currently working on a sample project that I can make public on Github. But indeed I can add the code of the build file to my question. That's not very critical ^^. – Fencer Jul 19 '19 at 12:01
  • 1
    Done. The only new library that has been added with the update of Spring Boot is `jasypt`. But of course almost all libraries have been updated, since Spring Boot manages most of them. – Fencer Jul 19 '19 at 12:12
  • 1
    Can you share link to your repository? – Bilbo Baggins Jul 19 '19 at 12:28
  • Yes, of course, as soon as I've finished cleaning the project from company secrets ;-) – Fencer Jul 19 '19 at 14:41
  • I shared a repository just now. – Fencer Jul 22 '19 at 21:44
  • In the interests of avoiding wasted effort, please be aware that the problem is also being investigated in [this Spring Boot issue](https://github.com/spring-projects/spring-boot/issues/17606) – Andy Wilkinson Jul 23 '19 at 09:44
  • @AndyWilkinson Thank you very much for your help in the Guthub-Issue. If you made a SO-answer out of it, I would gladly accept it. Please do so quickly, so that I can award the bounty. Currently it's still possible, otherwise the reputation will probably just be lost. – Fencer Jul 24 '19 at 08:26

0 Answers0