Galder Zamarreño created ELY-2064:
-------------------------------------
Summary: Elytron Quarkus integration not supporting key cloning
Key: ELY-2064
URL:
https://issues.redhat.com/browse/ELY-2064
Project: WildFly Elytron
Issue Type: Enhancement
Reporter: Galder Zamarreño
Assignee: Darran Lofthouse
Elytron Quarkus integration does not support key cloning, which causes Infinispan native
server to not be buildable. See
[
https://github.com/infinispan/infinispan-quarkus/issues/44|here] for details.
From an Elytron perspective, a way to solve this would be to have a substitution that
looks something like this, where MethodHandle uses are replaced by standard reflection:
{code:java}
package org.example.elytron.graal;
import com.oracle.svm.core.annotate.Substitute;
import com.oracle.svm.core.annotate.TargetClass;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.Key;
import java.security.PrivilegedAction;
import java.util.function.UnaryOperator;
import static java.security.AccessController.doPrivileged;
@TargetClass(className = "org.wildfly.security.key.KeyUtil$KeyClonerCreator")
final class Target_org_wildfly_security_key_KeyUtil_KeyClonerCreator
{
@Substitute
private UnaryOperator<Key> checkForCloneMethod(final Class<?> declType,
final Class<?> returnType)
{
System.out.printf("Call checkForCloneMethod(%s,%s)%n", declType,
returnType);
final Method method = doPrivileged(new PrivilegedAction<Method>()
{
@Override
public Method run()
{
try
{
final var cloneMethod =
declType.getDeclaredMethod("clone");
if (cloneMethod.getReturnType() == returnType)
return cloneMethod;
return null;
}
catch (NoSuchMethodException e)
{
return null;
}
}
});
if (method == null)
return null;
return new UnaryOperator<Key>()
{
@Override
public Key apply(Key key)
{
try
{
return (Key) method.invoke(key);
}
catch (RuntimeException | Error e)
{
throw e;
}
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
};
}
@Substitute
private UnaryOperator<Key> checkForCopyCtor(final Class<?> declType, final
Class<?> paramType)
{
System.out.printf("Call checkForCopyCtor(%s,%s)%n", declType,
paramType);
final Constructor<?> constructor = doPrivileged(new
PrivilegedAction<Constructor<?>>()
{
@Override
public Constructor<?> run()
{
try
{
return declType.getDeclaredConstructor(paramType);
}
catch (NoSuchMethodException e)
{
System.out.printf("Copy ctor in %s for parameter %s not
found%n", declType, paramType);
return null;
}
}
});
if (constructor == null)
return null;
return new UnaryOperator<Key>()
{
@Override
public Key apply(Key key)
{
try
{
return (Key) constructor.newInstance(key);
}
catch (RuntimeException | Error e)
{
throw e;
}
catch (Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
};
}
} {code}
These substitutions alone are not enough, there are also needs to be some reflection
registrations for the keys for which this is expected to work. As example:
{code:java}
package org.example.elytron.graal;
import com.oracle.svm.core.annotate.AutomaticFeature;
import org.example.elytron.Main;
import org.graalvm.nativeimage.hosted.Feature;
import org.graalvm.nativeimage.hosted.RuntimeReflection;
import javax.crypto.SecretKey;
import java.lang.reflect.UndeclaredThrowableException;
@AutomaticFeature
public class RuntimeReflectionRegistrations implements Feature
{
public void beforeAnalysis(BeforeAnalysisAccess access)
{
try
{
RuntimeReflection.register(Main.CopyConstructorSecretKey.class.getDeclaredConstructor(SecretKey.class));
RuntimeReflection.register(Main.CopyConstructorSecretKey.class.getDeclaredMethod("destroy"));
RuntimeReflection.register(Main.CloneMethodSecretKey.class.getDeclaredMethod("clone"));
RuntimeReflection.register(Main.CloneMethodSecretKey.class.getDeclaredMethod("destroy"));
}
catch (NoSuchMethodException e)
{
throw new UndeclaredThrowableException(e);
}
}
} {code}
[This main
class|https://github.com/galderz/mendrugo/blob/master/elytron-cloning/src...
these substitutions which have been verified to work with a couple of custom designed
secret keys that fall within the expected substitution.
The Elytron and Infinispan teams should work together to figure out which keys require
support from the reflection calls above.
All the code above can be found in [this sample
project.|https://github.com/galderz/mendrugo/tree/master/elytron-cloning]
--
This message was sent by Atlassian Jira
(v8.13.1#813001)