Skip to content

Commit c09a74b

Browse files
authored
[RORDEV-1491] ES 8.18.2 support (#1118)
1 parent 01a80ee commit c09a74b

File tree

7 files changed

+144
-12
lines changed

7 files changed

+144
-12
lines changed

ci/supported-es-versions/es8x.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
8.18.2
12
8.18.1
23
8.18.0
34
8.17.6

es818x/gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
latestSupportedEsVersion=8.18.1
1+
latestSupportedEsVersion=8.18.2

ror-tools-core/src/main/scala/tech/beshu/ror/tools/core/patches/Es818xPatch.scala

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,9 @@ import just.semver.SemVer
2020
import tech.beshu.ror.tools.core.patches.base.TransportNetty4AwareEsPatch
2121
import tech.beshu.ror.tools.core.patches.internal.RorPluginDirectory
2222
import tech.beshu.ror.tools.core.patches.internal.filePatchers.*
23+
import tech.beshu.ror.tools.core.patches.internal.modifiers.NoOpFileModifier
2324
import tech.beshu.ror.tools.core.patches.internal.modifiers.bytecodeJars.*
25+
import tech.beshu.ror.tools.core.utils.EsUtil.es8182
2426

2527
import scala.language.postfixOps
2628

@@ -32,6 +34,10 @@ private[patches] class Es818xPatch(rorPluginDirectory: RorPluginDirectory, esVer
3234
),
3335
new EntitlementJarPatchCreator(
3436
new ModifyEntitlementInitializationClass(esVersion),
37+
esVersion match {
38+
case v if v >= es8182 => new ModifyFilesEntitlementsValidationClass(esVersion)
39+
case _ => NoOpFileModifier
40+
},
3541
ModifyEntitlementRuntimePolicyParserClass,
3642
),
3743
new XPackCoreJarPatchCreator(

ror-tools-core/src/main/scala/tech/beshu/ror/tools/core/patches/base/EsPatch.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ object EsPatch {
3838
val rorPluginDirectory = new RorPluginDirectory(esDirectory)
3939
esDirectory.readEsVersion() match {
4040
case esVersion if esVersion >= es900 => new Es90xPatch(rorPluginDirectory, esVersion)
41-
case esVersion if esVersion >= es8180 => new Es90xPatch(rorPluginDirectory, esVersion)
41+
case esVersion if esVersion >= es8180 => new Es818xPatch(rorPluginDirectory, esVersion)
4242
case esVersion if esVersion >= es8150 => new Es815xPatch(rorPluginDirectory, esVersion)
4343
case esVersion if esVersion >= es8140 => new Es814xPatch(rorPluginDirectory, esVersion)
4444
case esVersion if esVersion >= es8130 => new Es813xPatch(rorPluginDirectory, esVersion)

ror-tools-core/src/main/scala/tech/beshu/ror/tools/core/patches/internal/modifiers/bytecodeJars/ModifyEntitlementInitializationClass.scala

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import java.io.{File, InputStream}
2727
* Modifies the EntitlementInitialization class to bypass forbidden file path validation
2828
* specifically for the ReadonlyREST plugin. This is necessary because ReadonlyREST
2929
* requires access to certain paths that would otherwise be blocked by Elasticsearch's
30-
* security entitlements system in versions 8.18.1+ and 9.0.1+.
30+
* security entitlements system in versions 8.18.1 and 9.0.1+.
3131
*/
3232
private[patches] class ModifyEntitlementInitializationClass(esVersion: SemVer)
3333
extends BytecodeJarModifier {
@@ -62,7 +62,7 @@ private[patches] class ModifyEntitlementInitializationClass(esVersion: SemVer)
6262
new DontValidateForbiddenPathsInCaseOfRorPlugin(
6363
super.visitMethod(access, name, descriptor, signature, exceptions)
6464
)
65-
case v if v >= es8181 =>
65+
case v if v == es8181 =>
6666
new DontValidateForbiddenPathsInCaseOfRorPlugin(
6767
super.visitMethod(access, name, descriptor, signature, exceptions)
6868
)
@@ -86,15 +86,13 @@ private[patches] class ModifyEntitlementInitializationClass(esVersion: SemVer)
8686
underlying.visitCode()
8787
val label0 = new Label()
8888
underlying.visitLabel(label0)
89-
underlying.visitLineNumber(407, label0)
9089
underlying.visitLdcInsn("readonlyrest")
9190
underlying.visitVarInsn(Opcodes.ALOAD, 0)
9291
underlying.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false)
9392
val label1 = new Label()
9493
underlying.visitJumpInsn(Opcodes.IFNE, label1)
9594
val label2 = new Label()
9695
underlying.visitLabel(label2)
97-
underlying.visitLineNumber(408, label2)
9896
underlying.visitVarInsn(Opcodes.ALOAD, 3)
9997
underlying.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Set", "iterator", "()Ljava/util/Iterator;", true)
10098
underlying.visitVarInsn(Opcodes.ASTORE, 4)
@@ -110,27 +108,23 @@ private[patches] class ModifyEntitlementInitializationClass(esVersion: SemVer)
110108
underlying.visitVarInsn(Opcodes.ASTORE, 5)
111109
val label4 = new Label()
112110
underlying.visitLabel(label4)
113-
underlying.visitLineNumber(409, label4)
114111
underlying.visitVarInsn(Opcodes.ALOAD, 2)
115112
underlying.visitVarInsn(Opcodes.ALOAD, 5)
116113
underlying.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/elasticsearch/entitlement/runtime/policy/FileAccessTree", "canRead", "(Ljava/nio/file/Path;)Z", false)
117114
val label5 = new Label()
118115
underlying.visitJumpInsn(Opcodes.IFEQ, label5)
119116
val label6 = new Label()
120117
underlying.visitLabel(label6)
121-
underlying.visitLineNumber(410, label6)
122118
underlying.visitVarInsn(Opcodes.ALOAD, 0)
123119
underlying.visitVarInsn(Opcodes.ALOAD, 1)
124120
underlying.visitVarInsn(Opcodes.ALOAD, 5)
125121
underlying.visitFieldInsn(Opcodes.GETSTATIC, "org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement$Mode", "READ", "Lorg/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement$Mode;")
126122
underlying.visitMethodInsn(Opcodes.INVOKESTATIC, "org/elasticsearch/entitlement/initialization/EntitlementInitialization", "buildValidationException", "(Ljava/lang/String;Ljava/lang/String;Ljava/nio/file/Path;Lorg/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement$Mode;)Ljava/lang/IllegalArgumentException;", false)
127123
underlying.visitInsn(Opcodes.ATHROW)
128124
underlying.visitLabel(label5)
129-
underlying.visitLineNumber(412, label5)
130125
underlying.visitFrame(Opcodes.F_SAME, 0, null, 0, null)
131126
underlying.visitJumpInsn(Opcodes.GOTO, label3)
132127
underlying.visitLabel(label1)
133-
underlying.visitLineNumber(414, label1)
134128
underlying.visitFrame(Opcodes.F_CHOP, 1, null, 0, null)
135129
underlying.visitInsn(Opcodes.RETURN)
136130
val label7 = new Label()
@@ -144,6 +138,4 @@ private[patches] class ModifyEntitlementInitializationClass(esVersion: SemVer)
144138
underlying.visitEnd()
145139
}
146140
}
147-
148141
}
149-
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
/*
2+
* This file is part of ReadonlyREST.
3+
*
4+
* ReadonlyREST is free software: you can redistribute it and/or modify
5+
* it under the terms of the GNU General Public License as published by
6+
* the Free Software Foundation, either version 3 of the License, or
7+
* (at your option) any later version.
8+
*
9+
* ReadonlyREST is distributed in the hope that it will be useful,
10+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
* GNU General Public License for more details.
13+
*
14+
* You should have received a copy of the GNU General Public License
15+
* along with ReadonlyREST. If not, see http://www.gnu.org/licenses/
16+
*/
17+
package tech.beshu.ror.tools.core.patches.internal.modifiers.bytecodeJars
18+
19+
import just.semver.SemVer
20+
import org.objectweb.asm.{ClassReader, ClassVisitor, ClassWriter, Label, MethodVisitor, Opcodes}
21+
import tech.beshu.ror.tools.core.patches.internal.modifiers.BytecodeJarModifier
22+
import tech.beshu.ror.tools.core.utils.EsUtil.es8182
23+
24+
import java.io.{File, InputStream}
25+
26+
/**
27+
* Modifies the EntitlementInitialization class to bypass forbidden file path validation
28+
* specifically for the ReadonlyREST plugin. This is necessary because ReadonlyREST
29+
* requires access to certain paths that would otherwise be blocked by Elasticsearch's
30+
* security entitlements system in versions 8.18.2+
31+
*/
32+
private[patches] class ModifyFilesEntitlementsValidationClass(esVersion: SemVer)
33+
extends BytecodeJarModifier {
34+
35+
override def apply(jar: File): Unit = {
36+
modifyFileInJar(
37+
jar = jar,
38+
filePathString = "org/elasticsearch/entitlement/initialization/FilesEntitlementsValidation.class",
39+
processFileContent = dontValidateForbiddenPathsInCaseOfRorPlugin
40+
)
41+
}
42+
43+
private def dontValidateForbiddenPathsInCaseOfRorPlugin(moduleInputStream: InputStream) = {
44+
val reader = new ClassReader(moduleInputStream)
45+
val writer = new ClassWriter(reader, 0)
46+
reader.accept(new EsClassVisitor(writer), 0)
47+
writer.toByteArray
48+
}
49+
50+
private class EsClassVisitor(writer: ClassWriter)
51+
extends ClassVisitor(Opcodes.ASM9, writer) {
52+
53+
override def visitMethod(access: Int,
54+
name: String,
55+
descriptor: String,
56+
signature: String,
57+
exceptions: Array[String]): MethodVisitor = {
58+
name match {
59+
case "validateReadFilesEntitlements" =>
60+
esVersion match {
61+
case v if v >= es8182 =>
62+
new DontValidateForbiddenPathsInCaseOfRorPlugin(
63+
super.visitMethod(access, name, descriptor, signature, exceptions)
64+
)
65+
case v =>
66+
super.visitMethod(access, name, descriptor, signature, exceptions)
67+
}
68+
case _ =>
69+
super.visitMethod(access, name, descriptor, signature, exceptions)
70+
}
71+
}
72+
}
73+
74+
private class DontValidateForbiddenPathsInCaseOfRorPlugin(underlying: MethodVisitor)
75+
extends MethodVisitor(Opcodes.ASM9) {
76+
77+
override def visitCode(): Unit = {
78+
underlying.visitCode()
79+
val label0 = new Label()
80+
underlying.visitLabel(label0)
81+
underlying.visitVarInsn(Opcodes.ALOAD, 3)
82+
underlying.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Set", "iterator", "()Ljava/util/Iterator;", true)
83+
underlying.visitVarInsn(Opcodes.ASTORE, 4)
84+
val label1 = new Label()
85+
underlying.visitLabel(label1)
86+
underlying.visitFrame(Opcodes.F_APPEND, 1, Array("java/util/Iterator"), 0, null)
87+
underlying.visitVarInsn(Opcodes.ALOAD, 4)
88+
underlying.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Iterator", "hasNext", "()Z", true)
89+
val label2 = new Label()
90+
underlying.visitJumpInsn(Opcodes.IFEQ, label2)
91+
underlying.visitVarInsn(Opcodes.ALOAD, 4)
92+
underlying.visitMethodInsn(Opcodes.INVOKEINTERFACE, "java/util/Iterator", "next", "()Ljava/lang/Object;", true)
93+
underlying.visitTypeInsn(Opcodes.CHECKCAST, "java/nio/file/Path")
94+
underlying.visitVarInsn(Opcodes.ASTORE, 5)
95+
val label3 = new Label()
96+
underlying.visitLabel(label3)
97+
underlying.visitLdcInsn("readonlyrest")
98+
underlying.visitVarInsn(Opcodes.ALOAD, 0)
99+
underlying.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "java/lang/String", "equals", "(Ljava/lang/Object;)Z", false)
100+
val label4 = new Label()
101+
underlying.visitJumpInsn(Opcodes.IFNE, label4)
102+
underlying.visitVarInsn(Opcodes.ALOAD, 2)
103+
underlying.visitVarInsn(Opcodes.ALOAD, 5)
104+
underlying.visitMethodInsn(Opcodes.INVOKEVIRTUAL, "org/elasticsearch/entitlement/runtime/policy/FileAccessTree", "canRead", "(Ljava/nio/file/Path;)Z", false)
105+
underlying.visitJumpInsn(Opcodes.IFEQ, label4)
106+
val label5 = new Label()
107+
underlying.visitLabel(label5)
108+
underlying.visitVarInsn(Opcodes.ALOAD, 0)
109+
underlying.visitVarInsn(Opcodes.ALOAD, 1)
110+
underlying.visitVarInsn(Opcodes.ALOAD, 5)
111+
underlying.visitFieldInsn(Opcodes.GETSTATIC, "org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement$Mode", "READ", "Lorg/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement$Mode;")
112+
underlying.visitMethodInsn(Opcodes.INVOKESTATIC, "org/elasticsearch/entitlement/initialization/FilesEntitlementsValidation", "buildValidationException", "(Ljava/lang/String;Ljava/lang/String;Ljava/nio/file/Path;Lorg/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement$Mode;)Ljava/lang/IllegalArgumentException;", false)
113+
underlying.visitInsn(Opcodes.ATHROW)
114+
underlying.visitLabel(label4)
115+
underlying.visitFrame(Opcodes.F_SAME, 0, null, 0, null)
116+
underlying.visitJumpInsn(Opcodes.GOTO, label1)
117+
underlying.visitLabel(label2)
118+
underlying.visitFrame(Opcodes.F_CHOP, 1, null, 0, null)
119+
underlying.visitInsn(Opcodes.RETURN)
120+
val label6 = new Label()
121+
underlying.visitLabel(label6)
122+
underlying.visitLocalVariable("forbiddenPath", "Ljava/nio/file/Path;", null, label3, label4, 5)
123+
underlying.visitLocalVariable("componentName", "Ljava/lang/String;", null, label0, label6, 0)
124+
underlying.visitLocalVariable("moduleName", "Ljava/lang/String;", null, label0, label6, 1)
125+
underlying.visitLocalVariable("fileAccessTree", "Lorg/elasticsearch/entitlement/runtime/policy/FileAccessTree;", null, label0, label6, 2)
126+
underlying.visitLocalVariable("readForbiddenPaths", "Ljava/util/Set;", "Ljava/util/Set<Ljava/nio/file/Path;>;", label0, label6, 3)
127+
underlying.visitMaxs(4, 6)
128+
underlying.visitEnd()
129+
}
130+
}
131+
132+
}

ror-tools-core/src/main/scala/tech/beshu/ror/tools/core/utils/EsUtil.scala

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ object EsUtil {
2525

2626
val es901: SemVer = SemVer.unsafeParse("9.0.1")
2727
val es900: SemVer = SemVer.unsafeParse("9.0.0")
28+
val es8182: SemVer = SemVer.unsafeParse("8.18.2")
2829
val es8181: SemVer = SemVer.unsafeParse("8.18.1")
2930
val es8180: SemVer = SemVer.unsafeParse("8.18.0")
3031
val es8150: SemVer = SemVer.unsafeParse("8.15.0")

0 commit comments

Comments
 (0)