From 0f522ade45e68e2c17ae75335614e692ea7fe7e8 Mon Sep 17 00:00:00 2001 From: Ryan Ernst Date: Tue, 1 Dec 2020 16:16:07 -0800 Subject: [PATCH] Force azure impl to be public The azure sdk internally dynamically constructs its client classes. However, one of these, for the blob storage is private. This has been fixed upstream, but until that is released, the client is unuseable without the newProxyInPackage permission. Rather than grant that permission, this commit makes the class in question public by patching the azure class file when building the azure repository plugin. relates https://github.com/Azure/azure-sdk-for-java/issues/17368 --- buildSrc/build.gradle | 2 + .../gradle/JavaClassPublicifier.java | 90 +++++++++++++++++++ .../azure-storage-blob/build.gradle | 32 +++++++ plugins/repository-azure/build.gradle | 9 +- .../azure-storage-blob-12.9.0.jar.sha1 | 1 - .../plugin-metadata/plugin-security.policy | 1 - 6 files changed, 125 insertions(+), 10 deletions(-) create mode 100644 buildSrc/src/main/java/org/elasticsearch/gradle/JavaClassPublicifier.java create mode 100644 plugins/repository-azure/azure-storage-blob/build.gradle delete mode 100644 plugins/repository-azure/licenses/azure-storage-blob-12.9.0.jar.sha1 diff --git a/buildSrc/build.gradle b/buildSrc/build.gradle index d7aea64b3496e..7a9cd601a2d75 100644 --- a/buildSrc/build.gradle +++ b/buildSrc/build.gradle @@ -104,6 +104,8 @@ dependencies { api 'com.avast.gradle:gradle-docker-compose-plugin:0.13.4' api 'org.apache.maven:maven-model:3.6.2' api 'com.networknt:json-schema-validator:1.0.36' + api 'org.ow2.asm:asm:9.0' + api 'org.ow2.asm:asm-tree:9.0' api "org.apache.httpcomponents:httpclient:${props.getProperty('httpclient')}" api "org.apache.httpcomponents:httpcore:${props.getProperty('httpcore')}" compileOnly "com.puppycrawl.tools:checkstyle:${props.getProperty('checkstyle')}" diff --git a/buildSrc/src/main/java/org/elasticsearch/gradle/JavaClassPublicifier.java b/buildSrc/src/main/java/org/elasticsearch/gradle/JavaClassPublicifier.java new file mode 100644 index 0000000000000..052c536718d10 --- /dev/null +++ b/buildSrc/src/main/java/org/elasticsearch/gradle/JavaClassPublicifier.java @@ -0,0 +1,90 @@ +/* + * Licensed to Elasticsearch under one or more contributor + * license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright + * ownership. Elasticsearch licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.elasticsearch.gradle; + +import org.gradle.api.DefaultTask; +import org.gradle.api.file.DirectoryProperty; +import org.gradle.api.tasks.Input; +import org.gradle.api.tasks.InputDirectory; +import org.gradle.api.tasks.OutputDirectory; +import org.gradle.api.tasks.TaskAction; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.ClassNode; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; + +import static org.objectweb.asm.Opcodes.ACC_PUBLIC; + +/** + * A task to manipulate an existing class file. + */ +public class JavaClassPublicifier extends DefaultTask { + + private String classFile; + private DirectoryProperty inputDir; + private DirectoryProperty outputDir; + + public JavaClassPublicifier() { + this.inputDir = getProject().getObjects().directoryProperty(); + this.outputDir = getProject().getObjects().directoryProperty(); + } + + @Input + public String getClassFile() { + return classFile; + } + + public void setClassFile(String classFile) { + this.classFile = classFile; + } + + @InputDirectory + public DirectoryProperty getInputDir() { + return inputDir; + } + + @OutputDirectory + public DirectoryProperty getOutputDir() { + return outputDir; + } + + @TaskAction + public void adapt() throws IOException { + final ClassNode classNode; + try (InputStream is = Files.newInputStream(inputDir.get().file(classFile).getAsFile().toPath())) { + ClassReader classReader = new ClassReader(is); + classNode = new ClassNode(); + classReader.accept(classNode, ClassReader.EXPAND_FRAMES); + } + + classNode.access |= ACC_PUBLIC; + + ClassWriter classWriter = new ClassWriter(ClassWriter.COMPUTE_FRAMES); + classNode.accept(classWriter); + + File outputFile = outputDir.get().file(classFile).getAsFile(); + outputFile.getParentFile().mkdirs(); + Files.write(outputFile.toPath(), classWriter.toByteArray()); + } +} diff --git a/plugins/repository-azure/azure-storage-blob/build.gradle b/plugins/repository-azure/azure-storage-blob/build.gradle new file mode 100644 index 0000000000000..027343c248703 --- /dev/null +++ b/plugins/repository-azure/azure-storage-blob/build.gradle @@ -0,0 +1,32 @@ +import org.elasticsearch.gradle.JavaClassPublicifier; + +apply plugin: 'elasticsearch.java' +apply plugin: 'com.github.johnrengelman.shadow' + +configurations { + originalJar { + transitive = false + } +} + +dependencies { + originalJar "com.azure:azure-storage-blob:${project.parent.versions.azure}" + implementation "com.azure:azure-storage-blob:${project.parent.versions.azure}" +} + +String blobsServiceClass = 'com/azure/storage/blob/implementation/BlobsImpl$BlobsService.class' + +tasks.create('extractBlobsServiceClass', Copy).configure { + from({ zipTree(configurations.originalJar.singleFile) }) { + include blobsServiceClass + } + into project.file('build/original') +} + +tasks.create('makeBlobsServicePublic', JavaClassPublicifier).configure { + classFile = blobsServiceClass + inputDir = project.layout.buildDirectory.dir('original') + outputDir = project.layout.buildDirectory.dir('modified') +} + +sourceSets.main.java.compiledBy(tasks.named('makeBlobsServicePublic')) { myTask -> myTask.outputDir } diff --git a/plugins/repository-azure/build.gradle b/plugins/repository-azure/build.gradle index 0f71cab0c76f4..a86ba1659034a 100644 --- a/plugins/repository-azure/build.gradle +++ b/plugins/repository-azure/build.gradle @@ -47,7 +47,7 @@ versions << [ ] dependencies { - api "com.azure:azure-storage-blob:${versions.azure}" + api project(path: 'azure-storage-blob', configuration: 'shadow') api "com.azure:azure-storage-blob-batch:12.6.0" api "com.azure:azure-storage-common:${versions.azure}" api "com.azure:azure-core-http-netty:${versions.azureCoreHttpNetty}" @@ -141,12 +141,6 @@ tasks.named("thirdPartyAudit").configure { 'kotlin.reflect.KDeclarationContainer', 'kotlin.sequences.Sequence', - // from com.azure.storage.blob.changefeed - 'com.azure.storage.internal.avro.implementation.AvroObject', - 'com.azure.storage.internal.avro.implementation.AvroReader', - 'com.azure.storage.internal.avro.implementation.AvroReaderFactory', - 'com.azure.storage.internal.avro.implementation.schema.AvroSchema', - // from io.netty.handler.codec.protobuf.ProtobufDecoder (netty) 'com.google.protobuf.ExtensionRegistry', 'com.google.protobuf.MessageLite$Builder', @@ -305,7 +299,6 @@ tasks.named("thirdPartyAudit").configure { 'reactor.core.publisher.UnsafeSupport' ) } - boolean useFixture = false def azureAddress = { diff --git a/plugins/repository-azure/licenses/azure-storage-blob-12.9.0.jar.sha1 b/plugins/repository-azure/licenses/azure-storage-blob-12.9.0.jar.sha1 deleted file mode 100644 index ebb91feb96a20..0000000000000 --- a/plugins/repository-azure/licenses/azure-storage-blob-12.9.0.jar.sha1 +++ /dev/null @@ -1 +0,0 @@ -0b2ef7730953058daa526d29c3fbb81470db6e8a \ No newline at end of file diff --git a/plugins/repository-azure/src/main/plugin-metadata/plugin-security.policy b/plugins/repository-azure/src/main/plugin-metadata/plugin-security.policy index e77cae1e1cd93..46267313d58c7 100644 --- a/plugins/repository-azure/src/main/plugin-metadata/plugin-security.policy +++ b/plugins/repository-azure/src/main/plugin-metadata/plugin-security.policy @@ -20,7 +20,6 @@ grant { // azure client opens socket connections for to access repository permission java.net.SocketPermission "*", "connect"; - permission java.lang.reflect.ReflectPermission "newProxyInPackage.com.azure.storage.blob.implementation"; // io.netty.util.concurrent.GlobalEventExecutor.startThread permission java.lang.RuntimePermission "setContextClassLoader"; // Used by jackson bean deserialization