Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Native server fails to build due to Elytron Credential unsupported combination #44

Closed
galderz opened this issue Jan 4, 2021 · 4 comments

Comments

@galderz
Copy link
Member

galderz commented Jan 4, 2021

Changes in introduced by ISPN-12101 are causing the native server to fail to build:

Error: com.oracle.graal.pointsto.constraints.UnsupportedFeatureException: Invoke with MethodHandle argument could not be reduced to at most a single call or single field access. The method handle must be a compile time constant, e.g., be loaded from a `static final` field. Method that contains the method handle invocation: java.lang.invoke.MethodHandle.invokeBasic(Object)
To diagnose the issue, you can add the option --report-unsupported-elements-at-runtime. The error is then reported at run time when the invoke is executed.
Trace: 
	at parsing java.lang.invoke.LambdaForm$MH/0x00000007c27e7440.invoke_MT(LambdaForm$MH)
Call path from entry point to java.lang.invoke.LambdaForm$MH/89291973.invoke_MT(Object, Object, Object): 
	at java.lang.invoke.LambdaForm$MH/0x00000007c27e7440.invoke_MT(LambdaForm$MH)
	at org.wildfly.security.key.KeyUtil$KeyClonerCreator.lambda$produceOp$4(KeyUtil.java:368)
	at org.wildfly.security.key.KeyUtil$KeyClonerCreator$$Lambda$4000/0x00000007c1ee6c40.apply(Unknown Source)

This has been cause as a result of 2 things coming together:

  1. Integrating credential store brings in 3 types into the close world analysis: org.wildfly.security.credential.SecretKeyCredential, org.wildfly.security.credential.KeyPairCredential and org.wildfly.security.credential.X509CertificateChainPrivateCredential. These are referenced from this calls:
│   │       │   │       │               │               │   │   │   │       │   │   │       ├── virtually calls org.infinispan.server.configuration.security.CredentialStoreConfigurationBuilder.getCredential(java.lang.String, java.lang.Class):org.wildfly.security.credential.Credential @bci=87
│   │       │   │       │               │               │   │   │   │       │   │   │       │   └── is overridden by org.infinispan.server.configuration.security.CredentialStoreConfigurationBuilder.getCredential(java.lang.String, java.lang.Class):org.wildfly.security.credential.Credential id=108269
│   │       │   │       │               │               │   │   │   │       │   │   │       │       └── virtually calls org.wildfly.security.credential.store.CredentialStoreSpi.retrieve(java.lang.String, java.lang.Class, java.lang.String, java.security.spec.AlgorithmParameterSpec, org.wildfly.security.credential.store.CredentialStore$ProtectionParameter):org.wildfly.security.credential.Credential @bci=67
│   │       │   │       │               │               │   │   │   │       │   │   │       │           └── is overridden by org.wildfly.security.credential.store.impl.KeyStoreCredentialStore.retrieve(java.lang.String, java.lang.Class, java.lang.String, java.security.spec.AlgorithmParameterSpec, org.wildfly.security.credential.store.CredentialStore$ProtectionParameter):org.wildfly.security.credential.Credential id=109616
│   │       │   │       │               │               │   │   │   │       │   │   │       │               ├── directly calls org.wildfly.security.credential.KeyPairCredential.<init>(java.security.KeyPair):void id-ref=87157 @bci=847

Those types have a clone method that invokes org.wildfly.security.key.KeyUtil.cloneKey and down that path you end up trying to use method handles. However, this alone is not enough for the close world analysis to decipher if clone is in use...

  1. Infinispan invokes clone on Credential, e.g. here:
│   │   │       │               │       │       │       ├── is overridden by org.infinispan.server.security.realm.EncryptedPropertiesSecurityRealm$1.getCredential(java.lang.Class, java.lang.String, java.security.spec.AlgorithmParameterSpec):org.wildfly.security.credential.Credential id=80691
│   │   │       │               │       │       │       │   ├── virtually calls org.wildfly.security.credential.Credential.clone():org.wildfly.security.credential.Credential @bci=57
│   │   │       │               │       │       │       │   │   ├── is overridden by org.wildfly.security.credential.KeyPairCredential.clone():org.wildfly.security.credential.Credential id=87531
│   │   │       │               │       │       │       │   │   │   └── directly calls org.wildfly.security.credential.KeyPairCredential.clone():org.wildfly.security.credential.KeyPairCredential id-ref=80095 @bci=1
  1. and 2) combined is what makes the thing explode.

A simple workaround, until Elytron has support for cloning keys in native, or GraalVM implements support for MethodHandle, would be to avoid using the generic clone().

I will create an Elytron issue shortly, with a potential solution for their Quarkus integration.

@galderz galderz mentioned this issue Jan 4, 2021
@galderz
Copy link
Member Author

galderz commented Jan 4, 2021

Details on the work required on the Elytron Quarkus integration can be found in ELY-2064.

@galderz
Copy link
Member Author

galderz commented Jan 4, 2021

One important detail: Infinispan Quarkus server could decide to implement its own substitutions if it knows what keys types are possible here. Moreover, if none of those keys will ever require reflection access to clone or copy constructor (see KeyCloneCreator source code for situations in which neither of those reflection calls are used), then they could be further simplified.

@galderz
Copy link
Member Author

galderz commented Jan 14, 2021

Screen Shot 2021-01-14 at 12 39 17

This is a visual representation of the paths shown as text in the description. It's using a slightly modified version of the PR here.

The node at the bottom is the cloneKey method. You see the different paths and right at the top that's the Infinispan point of entry. It'd be nice if you could make the nodes even bigger and show multiple fields at the same time...

ryanemerson added a commit to ryanemerson/infinispan-quarkus that referenced this issue Jan 15, 2021
@galderz
Copy link
Member Author

galderz commented Jan 18, 2021

Screen Shot 2021-01-18 at 11 46 08

That's the final iteration of my work here applied to this issue. I've added a display name that has single letter package name, with upper case letters of camel case class names and method name.

The other interesting thing is that the graph was produced with just one query like this (credit @michael-simons)

match p=((m:Method {name: "cloneKey"}) <- [r*1..4] - (n:Method))
with p
where last(nodes(p)).type starts with "org.infinispan" 
return nodes(p), relationships(p)

A query like match (m:Method {name: "cloneKey"}) <- [r*1..4] - (n:Method) return * would return all paths that lead to the method up to depth of 4. You could exclude things there and show the same thing, but Michael's query beats it 😎

Note the selected node is the Infinispan node. See at the bottom of screenshot for more details.

ryanemerson added a commit to ryanemerson/infinispan-quarkus that referenced this issue Jan 18, 2021
ryanemerson added a commit to ryanemerson/infinispan-quarkus that referenced this issue Jan 19, 2021
ryanemerson added a commit to ryanemerson/infinispan-quarkus that referenced this issue Jan 20, 2021
ryanemerson added a commit to ryanemerson/infinispan-quarkus that referenced this issue Jan 20, 2021
…mbination infinispan#44

Co-authored-by: Galder Zamarreño <galder@redhat.com>
wburns pushed a commit that referenced this issue Jan 21, 2021
…mbination #44

Co-authored-by: Galder Zamarreño <galder@redhat.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants