eclipse-ee4j / soteria

Soteria, a Jakarta Security implementation
Other
58 stars 30 forks source link

java.lang.IllegalAccessException: no such method...Caused by: java.lang.LinkageError: #192

Open glassfishrobot opened 7 years ago

glassfishrobot commented 7 years ago

I've run into an interesting problem....

I am using the version of Soteria built into "GlassFish Server Open Source Edition 5.0 (build 23)". What I'm working on is basically following the Soteria "app-custom" test application to create my own IdentityStore and Credential. My code can be found at "https://github.com/mjremijan/thoth-security-api/tree/master/11-security-api-get-cdi-bean/src/main/java/org/thoth/jeesa/security"

The issue I found is on 1st deploy to GlassFish I can access my application and it works fine. But if I Redeploy the application, the Redeploy works fine but when I access the application I get a 500 Internal Server Error. I put a try-catch block in my HttpAuthenticationMechanism implementation and was able to capture the following stack trace (see below) in the #validateRequest() method when the IdentityStoreHandler#validate() method is called.

Again, on 1st deploy there are no problems. This only happens on a Redeploy of the application. The work-around is to stop the GlassFish domain and start it again. When I restart the domain, the application starts working again and I don't get this linkage error. Not very good for development to have to restart the domain every time the application needs to be redeployed :(

I have only tried this on "GlassFish Server Open Source Edition 5.0 (build 23)". I've not tried it on any other "EE8" server.

java.lang.IllegalStateException: java.lang.IllegalAccessException: no such method: org.thoth.jeesa.security.identitystore.TestIdentityStore.validate(TestCredential)CredentialValidationResult/invokeSpecial at javax.security.enterprise.identitystore.IdentityStore.validate(IdentityStore.java:113) at org.glassfish.soteria.cdi.DefaultIdentityStoreHandler.validate(DefaultIdentityStoreHandler.java:97) at sun.reflect.GeneratedMethodAccessor290.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:497) at org.jboss.weld.bean.proxy.AbstractBeanInstance.invoke(AbstractBeanInstance.java:38) at org.jboss.weld.bean.proxy.ProxyMethodHandler.invoke(ProxyMethodHandler.java:100) at org.jboss.weldx.security.enterprise.identitystore.IdentityStoreHandler$1763020431$Proxy$_$$_WeldClientProxy.validate(Unknown Source) at org.thoth.jeesa.security.authentication.mechanism.TestHttpAuthenticationMechanism.validateRequest(TestHttpAuthenticationMechanism.java:67) at org.thoth.jeesa.security.authentication.mechanism.TestHttpAuthenticationMechanism$Proxy$_$$_WeldClientProxy.validateRequest(Unknown Source) at org.glassfish.soteria.mechanisms.jaspic.HttpBridgeServerAuthModule.validateRequest(HttpBridgeServerAuthModule.java:114) at org.glassfish.soteria.mechanisms.jaspic.DefaultServerAuthContext.validateRequest(DefaultServerAuthContext.java:76) at com.sun.web.security.RealmAdapter.validate(RealmAdapter.java:1675) at com.sun.web.security.RealmAdapter.invokeAuthenticateDelegate(RealmAdapter.java:1533) at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:577) at org.apache.catalina.core.StandardPipeline.doInvoke(StandardPipeline.java:620) at org.apache.catalina.core.StandardPipeline.doChainInvoke(StandardPipeline.java:596) at com.sun.enterprise.web.WebPipeline.invoke(WebPipeline.java:97) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) at org.apache.catalina.connector.CoyoteAdapter.doService(CoyoteAdapter.java:371) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:238) at com.sun.enterprise.v3.services.impl.ContainerMapper$HttpHandlerCallable.call(ContainerMapper.java:463) at com.sun.enterprise.v3.services.impl.ContainerMapper.service(ContainerMapper.java:168) at org.glassfish.grizzly.http.server.HttpHandler.runService(HttpHandler.java:206) at org.glassfish.grizzly.http.server.HttpHandler.doHandle(HttpHandler.java:180) at org.glassfish.grizzly.http.server.HttpServerFilter.handleRead(HttpServerFilter.java:242) at org.glassfish.grizzly.filterchain.ExecutorResolver$9.execute(ExecutorResolver.java:119) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeFilter(DefaultFilterChain.java:284) at org.glassfish.grizzly.filterchain.DefaultFilterChain.executeChainPart(DefaultFilterChain.java:201) at org.glassfish.grizzly.filterchain.DefaultFilterChain.execute(DefaultFilterChain.java:133) at org.glassfish.grizzly.filterchain.DefaultFilterChain.process(DefaultFilterChain.java:112) at org.glassfish.grizzly.ProcessorExecutor.execute(ProcessorExecutor.java:77) at org.glassfish.grizzly.nio.transport.TCPNIOTransport.fireIOEvent(TCPNIOTransport.java:539) at org.glassfish.grizzly.strategies.AbstractIOStrategy.fireIOEvent(AbstractIOStrategy.java:112) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.run0(WorkerThreadIOStrategy.java:117) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy.access$100(WorkerThreadIOStrategy.java:56) at org.glassfish.grizzly.strategies.WorkerThreadIOStrategy$WorkerThreadRunnable.run(WorkerThreadIOStrategy.java:137) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.doWork(AbstractThreadPool.java:593) at org.glassfish.grizzly.threadpool.AbstractThreadPool$Worker.run(AbstractThreadPool.java:573) at java.lang.Thread.run(Thread.java:745) Caused by: java.lang.IllegalAccessException: no such method: org.thoth.jeesa.security.identitystore.TestIdentityStore.validate(TestCredential)CredentialValidationResult/invokeSpecial at java.lang.invoke.MemberName.makeAccessException(MemberName.java:869) at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:990) at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1382) at java.lang.invoke.MethodHandles$Lookup.bind(MethodHandles.java:1146) at javax.security.enterprise.identitystore.IdentityStore.validate(IdentityStore.java:108) ... 39 more Caused by: java.lang.LinkageError: loader constraint violation: when resolving method "org.thoth.jeesa.security.identitystore.TestIdentityStore.validate(Lorg/thoth/jeesa/security/credential/TestCredential;)Ljavax/security/enterprise/identitystore/CredentialValidationResult;" the class loader (instance of org/apache/felix/framework/BundleWiringImpl$BundleClassLoaderJava5) of the current class, javax/security/enterprise/identitystore/IdentityStore, and the class loader (instance of org/glassfish/web/loader/WebappClassLoader) for the method's defining class, org/thoth/jeesa/security/identitystore/TestIdentityStore, have different Class objects for the type org/thoth/jeesa/security/credential/TestCredential used in the signature at java.lang.invoke.MethodHandleNatives.resolve(Native Method) at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:962) at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:987) ... 42 more

glassfishrobot commented 6 years ago
glassfishrobot commented 7 years ago

@mjremijan Commented I have an update to this. Also using GlassFish Server Open Source Edition 5.0 (build 23). I tried deploying 2 application to GlassFish Server Open Source Edition 5.0 (build 23), each of which has their own IdentityStore. 1st application deploys and runs ok. 2nd application deploys but when I try to run the application I get the same LinkageError as described above. So, this basically means I can only have 1 application deployed that uses a custom IdentityStore :(

glassfishrobot commented 7 years ago

@mjremijan Commented A bit more info on this. I just tried with Payara Server 5.0.0.174-SNAPSHOT #badassfish (build 36) and got the same results as GlassFish.

glassfishrobot commented 7 years ago

@arjantijms Commented Hmmm, I'm sure going to take a look at this.

If you want, in the meantime you could do a quick check on say WildFly 10 with Soteria bundled in the war (if you're using a maven project just don't make the dependency provided).

glassfishrobot commented 7 years ago

@mjremijan Commented I have an additional update on this. I was playing around with them IdentityStore implementation. If found that if my validate method looks like this:

public CredentialValidationResult validate(TestCredential credential) { ... }

Then I get the Linkage errors as described above. However, if I change the method to look like this:

@Override public CredentialValidationResult validate(Credential credential) { ... }

Then the problem with the linkage error goes away. Unfortunately, with the latter, a typecast is needed to get to the concrete Credential object.

So to get things working after redeployment, the 2nd method signature is needed. Not sure if this is a bug or not, i'll let you guys decide.

The former method signature is used in the Soteria "test/app-custom/src/main/java/org/glassfish/soteria/test/TestIdentityStore.java" as:

public CredentialValidationResult validate(UsernamePasswordCredential usernamePasswordCredential) { ... }

I was basing my code off this example. So maybe this example needs to be updated?

glassfishrobot commented 7 years ago

@arjantijms Commented By using the @Override public CredentialValidationResult validate(Credential credential) { ... } version you override the convenience method that does this type case essentially for you.

It's this default method:

    default CredentialValidationResult validate(Credential credential) {
        try {
            return CredentialValidationResult.class.cast(
                    MethodHandles.lookup()
                                 .bind(this, "validate", methodType(CredentialValidationResult.class, credential.getClass()))
                                 .invoke(credential));
        } catch (NoSuchMethodException e) {
            return NOT_VALIDATED_RESULT;
        } catch (Throwable e) {
            throw new IllegalStateException(e);
        }
    }

As you can see it uses some MethodHandle magic to find the right method.

glassfishrobot commented 7 years ago

@mjremijan Commented After changing my code to use the exact method signature @Override public CredentialValidationResult validate(Credential credential) { ... } it's working fine in both "GlassFish Server Open Source Edition 5.0 (build 23)" and "Payara Server 5.0.0.174-SNAPSHOT #badassfish (build 36)".

ggam commented 6 years ago

@mjremijan if I understand it correctly, this was a fault in your code that was already solved. Can we close this issue?

cghislai commented 5 years ago

Im running into the same issue using wildfly 16 docker image, shipping soteria 1.0. It happens only on subsequent deployment in my case: If I start the image, then make a first deployment of my ear using cargo, it works fine. If I redeploy the same ear using cargo without recreating the container, I run into this issue. So far only involving a single of the few identity stores present in the archive. The identity store overload seems correct:

    public CredentialValidationResult validate(AuthTokenCredential authTokenCredential) {
   }

With AuthTokenCredential a simple pojo class extending Credential. The stack:

2019-04-04 06:35:36,227 ERROR [io.undertow.request] (default task-1) UT005023: Exception handling request to /Gestemps-ws/front/user/me/token: java.lang.IllegalStateException: java.lang.IllegalAccessException: no such method: be.valuya.gestemps.auth.identitystore.GestempsUserTokenIdentityStore.validate(AuthTokenCredential)CredentialValidationResult/invokeSpecial
    at javax.security.enterprise.api@1.0//javax.security.enterprise.identitystore.IdentityStore.validate(IdentityStore.java:113)
    at deployment.Gestemps-ear.ear.Gestemps-ejb-2019.04.02-SNAPSHOT.jar//be.valuya.gestemps.auth.identitystore.GestempsUserTokenIdentityStore$Proxy$_$$_WeldClientProxy.validate(Unknown Source)
    at org.glassfish.soteria@1.0//org.glassfish.soteria.cdi.DefaultIdentityStoreHandler.validate(DefaultIdentityStoreHandler.java:97)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
...
Caused by: java.lang.IllegalAccessException: no such method: be.valuya.gestemps.auth.identitystore.GestempsUserTokenIdentityStore.validate(AuthTokenCredential)CredentialValidationResult/invokeSpecial
    at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:959)
    at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1101)
    at java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:2030)
    at java.base/java.lang.invoke.MethodHandles$Lookup.bind(MethodHandles.java:1694)
    at javax.security.enterprise.api@1.0//javax.security.enterprise.identitystore.IdentityStore.validate(IdentityStore.java:108)
    ... 70 more
Caused by: java.lang.LinkageError: loader constraint violation: when resolving method "be.valuya.gestemps.auth.identitystore.GestempsUserTokenIdentityStore.validate(Lbe/valuya/gestemps/auth/identitystore/AuthTokenCredential;)Ljavax/security/enterprise/identitystore/CredentialValidationResult;" the class loader 'javax.security.enterprise.api@1.0' @32c333bf (instance of org.jboss.modules.ModuleClassLoader, child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) of the current class, javax/security/enterprise/identitystore/IdentityStore, and the class loader 'deployment.Gestemps-ear.ear.Gestemps-ejb-2019.04.02-SNAPSHOT.jar' @54c15c15 (instance of org.jboss.modules.ModuleClassLoader, child of 'app' jdk.internal.loader.ClassLoaders$AppClassLoader) for the method's defining class, be/valuya/gestemps/auth/identitystore/GestempsUserTokenIdentityStore, have different Class objects for the type be/valuya/gestemps/auth/identitystore/AuthTokenCredential used in the signature
    at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:1070)
    at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1098)
    ... 73 more

I will be testing previous wildfly and report

cghislai commented 5 years ago

Reverting to previous wildfly version did not change anything. Overriding the IdentityStore#validate method (taking Credential as argument) rather that implementing one handling an application-typed credential fixed the issue, like for the original poster. So, in a custom identity store deployed in an ejb part of an ear on a wildfly 16 server, implementing:

nuzayats commented 5 years ago

I've encountered this with WildFly 16 too.

I believe application-typed implementations should work as it's documented in javax.security.enterprise.identitystore.IdentityStore.

arjantijms commented 5 years ago

Would be interesting to see how Open Liberty behaves here, since they use another implementation of EE Security.