繁体   English   中英

如何用自定义 SPI 替换核心类/功能?

[英]How to replace core classes/functionalities with a custom SPI?

我正在尝试通过自定义 SPI 将一些后量子密钥算法(来自 liboqs-java)添加到 Keycloak。 我可以使用我添加的算法生成密钥,但是在操作它们时遇到了一些问题。

Keycloak 在使用我的新算法处理密钥时遇到问题......我认为 Java BouncyCastle 无法识别后量子算法(例如 Dilithium2),它会导致系统崩溃。

我在 BCPemUtilsProvider Keycloak class 上遇到了 JcaPEMWriter BouncyCastle class 的问题。 我的解决方案是重写 BCPemUtilsProvider,这样我就可以替换 BouncyCastle 函数,但为了做到这一点,我需要从 Keycloak 更改一个核心文件并重新编译整个项目,这将花费大量时间,对于每个微小的更改。

我想通过 SPI(如果可能的话)或一些轻量级的解决方案来解决这个问题,所以我可以在实际时间内进行测试。 有没有办法在不重新编译整个 Keycloak 的情况下更改核心功能(或者,也许是我没有看到的另一个解决方案)?

提前致谢!!

顺便说一下,这是生成密钥的代码:

public AbstractGeneratedDLSecretKeyProvider(ComponentModel model, KeyUse use, String type, String algorithm) {
        this.status = KeyStatus.from(model.get(Attributes.ACTIVE_KEY, true), model.get(Attributes.ENABLED_KEY, true));
        this.kid = model.get(Attributes.KID_KEY);
        this.model = model;
        this.use = use;
        this.type = type;
        this.algorithm = algorithm;

        if (model.hasNote(PrivateKey.class.getName()) && model.hasNote(PublicKey.class.getName())) {
            privateKey = model.getNote(PrivateKey.class.getName());
            publicKey = model.getNote(PublicKey.class.getName());
        } else {
            Signature signer = new Signature("Dilithium2");

            signer.generate_keypair();

            privateKey = new DLPrivateKey(signer.export_secret_key());
            publicKey = new DLPublicKey(signer.export_public_key());

            model.setNote(PrivateKey.class.getName(), privateKey);
            model.setNote(PublicKey.class.getName(), publicKey);
        }
    }

这是我面临的错误:

2022-08-25 21:06:18,476 ERROR [org.keycloak.services.error.KeycloakErrorHandler] (executor-thread-0) Uncaught server error: org.keycloak.common.util.PemException: java.lang.IllegalArgumentException: failed to construct sequence from byte[]: Extra data detected in stream
    at org.keycloak.crypto.def.BCPemUtilsProvider.encode(BCPemUtilsProvider.java:56)
    at org.keycloak.common.crypto.PemUtilsProvider.encodeKey(PemUtilsProvider.java:129)
    at org.keycloak.common.util.PemUtils.encodeKey(PemUtils.java:98)
    at org.keycloak.services.resources.admin.KeyResource.toKeyMetadataRepresentation(KeyResource.java:83)
    at org.keycloak.services.resources.admin.KeyResource.lambda$getKeyMetadata$0(KeyResource.java:67)
    at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:195)
    at java.base/java.util.stream.Streams$StreamBuilderImpl.forEachRemaining(Streams.java:411)
    at java.base/java.util.stream.ReferencePipeline$Head.forEach(ReferencePipeline.java:658)
    at java.base/java.util.stream.ReferencePipeline$7$1.accept(ReferencePipeline.java:274)
    at java.base/java.util.ArrayList$ArrayListSpliterator.forEachRemaining(ArrayList.java:1655)
    at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:484)
    at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:474)
    at java.base/java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:913)
    at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
    at java.base/java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:578)
    at org.keycloak.services.resources.admin.KeyResource.getKeyMetadata(KeyResource.java:69)
    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)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:170)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:130)
    at org.jboss.resteasy.core.ResourceMethodInvoker.internalInvokeOnTarget(ResourceMethodInvoker.java:660)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTargetAfterFilter(ResourceMethodInvoker.java:524)
    at org.jboss.resteasy.core.ResourceMethodInvoker.lambda$invokeOnTarget$2(ResourceMethodInvoker.java:474)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:476)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:434)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:192)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:152)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invokeOnTargetObject(ResourceLocatorInvoker.java:183)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:141)
    at org.jboss.resteasy.core.ResourceLocatorInvoker.invoke(ResourceLocatorInvoker.java:32)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:492)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$invoke$4(SynchronousDispatcher.java:261)
    at org.jboss.resteasy.core.SynchronousDispatcher.lambda$preprocess$0(SynchronousDispatcher.java:161)
    at org.jboss.resteasy.core.interception.jaxrs.PreMatchContainerRequestContext.filter(PreMatchContainerRequestContext.java:364)
    at org.jboss.resteasy.core.SynchronousDispatcher.preprocess(SynchronousDispatcher.java:164)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:247)
    at io.quarkus.resteasy.runtime.standalone.RequestDispatcher.service(RequestDispatcher.java:73)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.dispatch(VertxRequestHandler.java:151)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:82)
    at io.quarkus.resteasy.runtime.standalone.VertxRequestHandler.handle(VertxRequestHandler.java:42)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
    at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:67)
    at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:55)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
    at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:380)
    at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:358)
    at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1212)
    at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
    at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
    at org.keycloak.quarkus.runtime.integration.web.QuarkusRequestFilter.lambda$createBlockingHandler$1(QuarkusRequestFilter.java:90)
    at io.vertx.core.impl.ContextImpl.lambda$null$0(ContextImpl.java:159)
    at io.vertx.core.impl.AbstractContext.dispatch(AbstractContext.java:100)
    at io.vertx.core.impl.ContextImpl.lambda$executeBlocking$1(ContextImpl.java:157)
    at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:545)
    at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
    at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
    at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
    at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
    at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
    at java.base/java.lang.Thread.run(Thread.java:829)
Caused by: java.lang.IllegalArgumentException: failed to construct sequence from byte[]: Extra data detected in stream
    at org.bouncycastle.asn1.ASN1Sequence.getInstance(ASN1Sequence.java:92)
    at org.bouncycastle.asn1.x509.SubjectPublicKeyInfo.getInstance(SubjectPublicKeyInfo.java:43)
    at org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator.convertObject(Unknown Source)
    at org.bouncycastle.openssl.jcajce.JcaMiscPEMGenerator.<init>(Unknown Source)
    at org.bouncycastle.openssl.jcajce.JcaPEMWriter.writeObject(Unknown Source)
    at org.bouncycastle.openssl.jcajce.JcaPEMWriter.writeObject(Unknown Source)
    at org.keycloak.crypto.def.BCPemUtilsProvider.encode(BCPemUtilsProvider.java:50)
    ... 68 more

Brendon Vicente,Custom ClassLoader 可以帮助您。

public class LoadClassInfo extends ClassLoader{
    private ClassLoader classLoader;
    private String pack_name;
    public LoadClassInfo(ClassLoader parent,String pack_name) {
        super(parent);
        this.classLoader = parent;
        this.pack_name = pack_name;
    }
    public Class<?> loadClass(String name) throws ClassNotFoundException {
       if(!name.contains(pack_name))return super.loadClass(name);
        try {
            if(!name.matches("(.+)\\.(.+)\\.(.+)"))return null;
            InputStream input = classLoader.getResourceAsStream(String.format("%s.class",name.replace(".","/")));
            ByteArrayOutputStream buffer = new ByteArrayOutputStream();
            int data = input.read();
            while(data != -1){
                buffer.write(data);
                data = input.read();
            }
            input.close();
            byte[] classData = buffer.toByteArray();
            System.out.println("name "+name);
            return defineClass(name,classData, 0, classData.length);
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }
}
ScheduledThreadPoolExecutor scheduleds = new ScheduledThreadPoolExecutor(1);
    ClassLoader classLoader;
    String file_path = (classLoader = ClassLoader.getSystemClassLoader())
            .getResource("com.imageutil".replace(".","/")).getPath()
            .substring(1);
    try {
        Map<String,String> maps = Files.list(Paths.get(file_path))
        .filter(x->x.getFileName().toString().endsWith(".class"))
        .collect(Collectors.toMap(m->{
            return m.toString();
        },m->{
            try {
                return String.valueOf(Files.size(m));
            } catch (IOException e) {
                e.printStackTrace();
                return null;
            }
        },(a,b)->a));
        maps.forEach((m,n)->{
            System.out.println(m+" : "+n);
        });
        
        scheduleds.scheduleAtFixedRate(()->{
            try {
                Path[] paths = Files.list(Paths.get(file_path)).toArray(Path[]::new);
                for (Path string : paths) {
                    String class_path = string.toString();
                    String last_time = String.valueOf(Files.size(string));
                    if(Objects.equals(last_time,maps.get(class_path)))continue;
                    String pack_name = class_path.split("classes")[1].replace("\\", ".").substring(1);
                    String class_name = pack_name.substring(0, pack_name.lastIndexOf("."));
                    LoadClassInfo loadClassInfos = new LoadClassInfo(classLoader,"com.imageutil");
                    Class<?> classs = loadClassInfos.loadClass(class_name);
                    classs.newInstance();
                    maps.put(class_path,last_time);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        },1,1,TimeUnit.SECONDS);
        
        
    } catch (IOException e) {
        e.printStackTrace();

    }

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM