diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a031169b7..13d0d0dc84 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,6 +33,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Removed +- Removed unused support for custom User object serialization ([#5339](https://github.com/opensearch-project/security/pull/5339)) + ### Fixed - Corrections in DlsFlsFilterLeafReader regarding PointVales and object valued attributes ([#5303](https://github.com/opensearch-project/security/pull/5303)) - Fix issue computing diffs in compliance audit log when writing to security index ([#5279](https://github.com/opensearch-project/security/pull/5279)) diff --git a/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java b/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java index 6f974ecdb3..58c4dfda5d 100755 --- a/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java +++ b/src/main/java/com/amazon/dlic/auth/ldap/LdapUser.java @@ -11,13 +11,10 @@ package com.amazon.dlic.auth.ldap; -import java.io.IOException; import java.util.Collections; import java.util.HashMap; import java.util.Map; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.security.auth.ldap.util.Utils; import org.opensearch.security.support.WildcardMatcher; import org.opensearch.security.user.AuthCredentials; @@ -58,12 +55,6 @@ public LdapUser( attributes.putAll(extractLdapAttributes(originalUsername, userEntry, customAttrMaxValueLen, allowlistedCustomLdapAttrMatcher)); } - public LdapUser(StreamInput in) throws IOException { - super(in); - userEntry = null; - originalUsername = in.readString(); - } - /** * May return null because ldapEntry is transient * @@ -107,10 +98,4 @@ public static Map extractLdapAttributes( } return Collections.unmodifiableMap(attributes); } - - @Override - public void writeTo(StreamOutput out) throws IOException { - super.writeTo(out); - out.writeString(originalUsername); - } } diff --git a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java index 302ac96442..65094ac94d 100644 --- a/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java +++ b/src/main/java/org/opensearch/security/auditlog/impl/AbstractAuditLog.java @@ -775,8 +775,7 @@ private TransportAddress getRemoteAddress() { if (address == null && threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS_HEADER) != null) { address = new TransportAddress( (InetSocketAddress) Base64Helper.deserializeObject( - threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS_HEADER), - threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION) + threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS_HEADER) ) ); } @@ -787,8 +786,7 @@ private String getUser() { User user = threadPool.getThreadContext().getTransient(ConfigConstants.OPENDISTRO_SECURITY_USER); if (user == null && threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER) != null) { user = (User) Base64Helper.deserializeObject( - threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER), - threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION) + threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER) ); } return user == null ? null : user.getName(); diff --git a/src/main/java/org/opensearch/security/auth/UserInjector.java b/src/main/java/org/opensearch/security/auth/UserInjector.java index 65a7055238..1e775d6e33 100644 --- a/src/main/java/org/opensearch/security/auth/UserInjector.java +++ b/src/main/java/org/opensearch/security/auth/UserInjector.java @@ -26,7 +26,6 @@ package org.opensearch.security.auth; -import java.io.IOException; import java.io.ObjectStreamException; import java.net.InetAddress; import java.net.UnknownHostException; @@ -39,8 +38,6 @@ import org.apache.logging.log4j.Logger; import org.opensearch.common.settings.Settings; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; import org.opensearch.core.common.transport.TransportAddress; import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.filter.SecurityRequestChannel; @@ -73,11 +70,6 @@ public InjectedUser(String name) { super(name); } - public InjectedUser(StreamInput in) throws IOException { - super(in); - this.setInjected(true); - } - private Object writeReplace() throws ObjectStreamException { User user = new User(getName()); user.addRoles(getRoles()); @@ -106,11 +98,6 @@ public void setTransportAddress(String addr) throws UnknownHostException, Illega this.transportAddress = new TransportAddress(iAdress, port); } - - @Override - public void writeTo(StreamOutput out) throws IOException { - super.writeTo(out); - } } public InjectedUser getInjectedUser() { diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index 6b23fb6b53..2e0b61289f 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -184,10 +184,6 @@ private void ap threadContext.putTransient(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN, Origin.LOCAL.toString()); } - if (threadContext.getTransient(ConfigConstants.USE_JDK_SERIALIZATION) == null) { - threadContext.putTransient(ConfigConstants.USE_JDK_SERIALIZATION, true); - } - final ComplianceConfig complianceConfig = auditLog.getComplianceConfig(); if (complianceConfig != null && complianceConfig.isEnabled()) { attachSourceFieldContext(request); diff --git a/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLRequestHandler.java b/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLRequestHandler.java index 7002171595..8350908890 100644 --- a/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLRequestHandler.java +++ b/src/main/java/org/opensearch/security/ssl/transport/SecuritySSLRequestHandler.java @@ -34,7 +34,6 @@ import org.opensearch.security.ssl.util.ExceptionUtils; import org.opensearch.security.ssl.util.SSLRequestHelper; import org.opensearch.security.support.ConfigConstants; -import org.opensearch.security.support.SerializationFormat; import org.opensearch.tasks.Task; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.TransportChannel; @@ -91,11 +90,6 @@ public final void messageReceived(T request, TransportChannel channel, Task task channel = getInnerChannel(channel); } - threadContext.putTransient( - ConfigConstants.USE_JDK_SERIALIZATION, - SerializationFormat.determineFormat(channel.getVersion()) == SerializationFormat.JDK - ); - if (SSLRequestHelper.containsBadHeader(threadContext, "_opendistro_security_ssl_")) { final Exception exception = ExceptionUtils.createBadHeaderException(); channel.sendResponse(exception); diff --git a/src/main/java/org/opensearch/security/support/Base64CustomHelper.java b/src/main/java/org/opensearch/security/support/Base64CustomHelper.java deleted file mode 100644 index 30fab31907..0000000000 --- a/src/main/java/org/opensearch/security/support/Base64CustomHelper.java +++ /dev/null @@ -1,227 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.support; - -import java.io.IOException; -import java.io.Serializable; - -import com.google.common.base.Preconditions; -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; -import com.google.common.io.BaseEncoding; - -import org.opensearch.OpenSearchException; -import org.opensearch.common.Nullable; -import org.opensearch.common.io.stream.BytesStreamOutput; -import org.opensearch.core.common.Strings; -import org.opensearch.core.common.io.stream.BytesStreamInput; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.Writeable; -import org.opensearch.security.auth.UserInjector; -import org.opensearch.security.user.User; - -import com.amazon.dlic.auth.ldap.LdapUser; - -import static org.opensearch.security.support.SafeSerializationUtils.prohibitUnsafeClasses; - -/** - * Provides support for Serialization/Deserialization of objects of supported classes into/from Base64 encoded stream - * using the OpenSearch's custom serialization protocol implemented by the StreamInput/StreamOutput classes. - */ -public class Base64CustomHelper { - - private enum CustomSerializationFormat { - - WRITEABLE(1), - STREAMABLE(2), - GENERIC(3); - - private final int id; - - CustomSerializationFormat(int id) { - this.id = id; - } - - static CustomSerializationFormat fromId(int id) { - switch (id) { - case 1: - return WRITEABLE; - case 2: - return STREAMABLE; - case 3: - return GENERIC; - default: - throw new IllegalArgumentException(String.format("%d is not a valid id", id)); - } - } - - } - - private static final BiMap, Integer> writeableClassToIdMap = HashBiMap.create(); - private static final StreamableRegistry streamableRegistry = StreamableRegistry.getInstance(); - - static { - registerAllWriteables(); - } - - protected static String serializeObject(final Serializable object) { - - Preconditions.checkArgument(object != null, "object must not be null"); - final BytesStreamOutput streamOutput = new SafeBytesStreamOutput(128); - Class clazz = object.getClass(); - try { - prohibitUnsafeClasses(clazz); - CustomSerializationFormat customSerializationFormat = getCustomSerializationMode(clazz); - switch (customSerializationFormat) { - case WRITEABLE: - streamOutput.writeByte((byte) CustomSerializationFormat.WRITEABLE.id); - streamOutput.writeByte((byte) getWriteableClassID(clazz).intValue()); - ((Writeable) object).writeTo(streamOutput); - break; - case STREAMABLE: - streamOutput.writeByte((byte) CustomSerializationFormat.STREAMABLE.id); - streamableRegistry.writeTo(streamOutput, object); - break; - case GENERIC: - streamOutput.writeByte((byte) CustomSerializationFormat.GENERIC.id); - streamOutput.writeGenericValue(object); - break; - default: - throw new IllegalArgumentException( - String.format("Could not determine custom serialization mode for class %s", clazz.getName()) - ); - } - } catch (final Exception e) { - throw new OpenSearchException("Instance {} of class {} is not serializable", e, object, object.getClass()); - } - final byte[] bytes = streamOutput.bytes().toBytesRef().bytes; - streamOutput.close(); - return BaseEncoding.base64().encode(bytes); - } - - protected static Serializable deserializeObject(final String string) { - - Preconditions.checkArgument(!Strings.isNullOrEmpty(string), "object must not be null or empty"); - final byte[] bytes = BaseEncoding.base64().decode(string); - Serializable obj = null; - try (final BytesStreamInput streamInput = new SafeBytesStreamInput(bytes)) { - CustomSerializationFormat serializationFormat = CustomSerializationFormat.fromId(streamInput.readByte()); - switch (serializationFormat) { - case WRITEABLE: - final int classId = streamInput.readByte(); - Class clazz = getWriteableClassFromId(classId); - obj = (Serializable) clazz.getConstructor(StreamInput.class).newInstance(streamInput); - break; - case STREAMABLE: - obj = (Serializable) streamableRegistry.readFrom(streamInput); - break; - case GENERIC: - obj = (Serializable) streamInput.readGenericValue(); - break; - default: - throw new IllegalArgumentException("Could not determine custom deserialization mode"); - } - prohibitUnsafeClasses(obj.getClass()); - return obj; - } catch (final Exception e) { - throw new OpenSearchException(e); - } - } - - private static boolean isWriteable(Class clazz) { - return Writeable.class.isAssignableFrom(clazz); - } - - /** - * Returns integer ID for the registered Writeable class - *
- * Protected for testing - */ - protected static Integer getWriteableClassID(Class clazz) { - if (!isWriteable(clazz)) { - throw new OpenSearchException("clazz should implement Writeable ", clazz); - } - if (!writeableClassToIdMap.containsKey(clazz)) { - throw new OpenSearchException("Writeable clazz not registered ", clazz); - } - return writeableClassToIdMap.get(clazz); - } - - private static Class getWriteableClassFromId(int id) { - return writeableClassToIdMap.inverse().get(id); - } - - /** - * Registers the given Writeable class for custom serialization by assigning an incrementing integer ID - * IDs are stored in a HashBiMap - * @param clazz class to be registered - */ - private static void registerWriteable(Class clazz) { - if (writeableClassToIdMap.containsKey(clazz)) { - throw new OpenSearchException("writeable clazz is already registered ", clazz.getName()); - } - int id = writeableClassToIdMap.size() + 1; - writeableClassToIdMap.put(clazz, id); - } - - /** - * Registers all Writeable classes for custom serialization support. - * Removing existing classes / changing order of registration will cause a breaking change in the serialization protocol - * as registerWriteable assigns an incrementing integer ID to each of the classes in the order it is called - * starting from 1. - *
- * New classes can safely be added towards the end. - */ - private static void registerAllWriteables() { - registerWriteable(User.class); - registerWriteable(LdapUser.class); - registerWriteable(UserInjector.InjectedUser.class); - registerWriteable(SourceFieldsContext.class); - } - - private static CustomSerializationFormat getCustomSerializationMode(Class clazz) { - if (isWriteable(clazz)) { - return CustomSerializationFormat.WRITEABLE; - } else if (streamableRegistry.isStreamable(clazz)) { - return CustomSerializationFormat.STREAMABLE; - } else { - return CustomSerializationFormat.GENERIC; - } - } - - private static class SafeBytesStreamOutput extends BytesStreamOutput { - - public SafeBytesStreamOutput(int expectedSize) { - super(expectedSize); - } - - @Override - public void writeGenericValue(@Nullable Object value) throws IOException { - prohibitUnsafeClasses(value.getClass()); - super.writeGenericValue(value); - } - } - - private static class SafeBytesStreamInput extends BytesStreamInput { - - public SafeBytesStreamInput(byte[] bytes) { - super(bytes); - } - - @Override - public Object readGenericValue() throws IOException { - Object object = super.readGenericValue(); - prohibitUnsafeClasses(object.getClass()); - return object; - } - } -} diff --git a/src/main/java/org/opensearch/security/support/Base64Helper.java b/src/main/java/org/opensearch/security/support/Base64Helper.java index 7e104ace54..6c28e0a6ea 100644 --- a/src/main/java/org/opensearch/security/support/Base64Helper.java +++ b/src/main/java/org/opensearch/security/support/Base64Helper.java @@ -26,71 +26,93 @@ package org.opensearch.security.support; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.InvalidClassException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.ObjectStreamClass; +import java.io.OutputStream; import java.io.Serializable; +import com.google.common.base.Preconditions; +import com.google.common.io.BaseEncoding; + +import org.opensearch.OpenSearchException; +import org.opensearch.core.common.Strings; + +import static org.opensearch.security.support.SafeSerializationUtils.isSafeClass; + +/** + * Provides support for Serialization/Deserialization of objects of supported classes into/from Base64 encoded stream + * using JDK's in-built serialization protocol implemented by the ObjectOutputStream and ObjectInputStream classes. + */ public class Base64Helper { - public static String serializeObject(final Serializable object, final boolean useJDKSerialization) { - return useJDKSerialization ? Base64JDKHelper.serializeObject(object) : Base64CustomHelper.serializeObject(object); + private final static class SafeObjectOutputStream extends ObjectOutputStream { + + static ObjectOutputStream create(ByteArrayOutputStream out) throws IOException { + return new Base64Helper.SafeObjectOutputStream(out); + } + + private SafeObjectOutputStream(OutputStream out) throws IOException { + super(out); + enableReplaceObject(true); + } + + @Override + protected Object replaceObject(Object obj) throws IOException { + Class clazz = obj.getClass(); + if (isSafeClass(clazz)) { + return obj; + } + throw new IOException("Unauthorized serialization attempt " + clazz.getName()); + } } public static String serializeObject(final Serializable object) { - return serializeObject(object, true); + + Preconditions.checkArgument(object != null, "object must not be null"); + + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try (final ObjectOutputStream out = Base64Helper.SafeObjectOutputStream.create(bos)) { + out.writeObject(object); + } catch (final Exception e) { + throw new OpenSearchException("Instance {} of class {} is not serializable", e, object, object.getClass()); + } + final byte[] bytes = bos.toByteArray(); + return BaseEncoding.base64().encode(bytes); } public static Serializable deserializeObject(final String string) { - return deserializeObject(string, true); - } - public static Serializable deserializeObject(final String string, final boolean useJDKDeserialization) { - return useJDKDeserialization ? Base64JDKHelper.deserializeObject(string) : Base64CustomHelper.deserializeObject(string); - } + Preconditions.checkArgument(!Strings.isNullOrEmpty(string), "object must not be null or empty"); - /** - * Ensures that the returned string is JDK serialized. - * - * If the supplied string is a custom serialized representation, will deserialize it and further serialize using - * JDK, otherwise returns the string as is. - * - * @param string original string, can be JDK or custom serialized - * @return jdk serialized string - */ - public static String ensureJDKSerialized(final String string) { - Serializable serializable; - try { - serializable = Base64Helper.deserializeObject(string, false); - } catch (Exception e) { - // We received an exception when de-serializing the given string. It is probably JDK serialized. - // Try to deserialize using JDK - Base64Helper.deserializeObject(string, true); - // Since we could deserialize the object using JDK, the string is already JDK serialized, return as is - return string; + final byte[] bytes = BaseEncoding.base64().decode(string); + final ByteArrayInputStream bis = new ByteArrayInputStream(bytes); + try (Base64Helper.SafeObjectInputStream in = new Base64Helper.SafeObjectInputStream(bis)) { + return (Serializable) in.readObject(); + } catch (final Exception e) { + throw new OpenSearchException(e); } - // If we see an exception now, we want the caller to see it - - return Base64Helper.serializeObject(serializable, true); } - /** - * Ensures that the returned string is custom serialized. - * - * If the supplied string is a JDK serialized representation, will deserialize it and further serialize using - * custom, otherwise returns the string as is. - * - * @param string original string, can be JDK or custom serialized - * @return custom serialized string - */ - public static String ensureCustomSerialized(final String string) { - Serializable serializable; - try { - serializable = Base64Helper.deserializeObject(string, true); - } catch (Exception e) { - // We received an exception when de-serializing the given string. It is probably custom serialized. - // Try to deserialize using custom - Base64Helper.deserializeObject(string, false); - // Since we could deserialize the object using custom, the string is already custom serialized, return as is - return string; + private final static class SafeObjectInputStream extends ObjectInputStream { + public SafeObjectInputStream(InputStream in) throws IOException { + super(in); + } + + @Override + protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { + + Class clazz = super.resolveClass(desc); + if (isSafeClass(clazz)) { + return clazz; + } + + throw new InvalidClassException("Unauthorized deserialization attempt ", clazz.getName()); } - // If we see an exception now, we want the caller to see it - - return Base64Helper.serializeObject(serializable, false); } } diff --git a/src/main/java/org/opensearch/security/support/Base64JDKHelper.java b/src/main/java/org/opensearch/security/support/Base64JDKHelper.java deleted file mode 100644 index a4ab87d813..0000000000 --- a/src/main/java/org/opensearch/security/support/Base64JDKHelper.java +++ /dev/null @@ -1,156 +0,0 @@ -/* - * Copyright 2015-2018 _floragunn_ GmbH - * Licensed 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. - */ - -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.support; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.InvalidClassException; -import java.io.ObjectInputStream; -import java.io.ObjectOutputStream; -import java.io.ObjectStreamClass; -import java.io.OutputStream; -import java.io.Serializable; -import java.security.AccessController; -import java.security.PrivilegedAction; - -import com.google.common.base.Preconditions; -import com.google.common.io.BaseEncoding; - -import org.opensearch.OpenSearchException; -import org.opensearch.SpecialPermission; -import org.opensearch.core.common.Strings; - -import static org.opensearch.security.support.SafeSerializationUtils.isSafeClass; - -/** - * Provides support for Serialization/Deserialization of objects of supported classes into/from Base64 encoded stream - * using JDK's in-built serialization protocol implemented by the ObjectOutputStream and ObjectInputStream classes. - */ -public class Base64JDKHelper { - - private final static class SafeObjectOutputStream extends ObjectOutputStream { - - private static final boolean useSafeObjectOutputStream = checkSubstitutionPermission(); - - @SuppressWarnings("removal") - private static boolean checkSubstitutionPermission() { - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - try { - sm.checkPermission(new SpecialPermission()); - - AccessController.doPrivileged((PrivilegedAction) () -> { - AccessController.checkPermission(SUBSTITUTION_PERMISSION); - return null; - }); - } catch (SecurityException e) { - return false; - } - } - return true; - } - - static ObjectOutputStream create(ByteArrayOutputStream out) throws IOException { - try { - return useSafeObjectOutputStream ? new SafeObjectOutputStream(out) : new ObjectOutputStream(out); - } catch (SecurityException e) { - // As we try to create SafeObjectOutputStream only when necessary permissions are granted, we should - // not reach here, but if we do, we can still return ObjectOutputStream after resetting ByteArrayOutputStream - out.reset(); - return new ObjectOutputStream(out); - } - } - - @SuppressWarnings("removal") - private SafeObjectOutputStream(OutputStream out) throws IOException { - super(out); - - SecurityManager sm = System.getSecurityManager(); - if (sm != null) { - sm.checkPermission(new SpecialPermission()); - } - - AccessController.doPrivileged((PrivilegedAction) () -> enableReplaceObject(true)); - } - - @Override - protected Object replaceObject(Object obj) throws IOException { - Class clazz = obj.getClass(); - if (isSafeClass(clazz)) { - return obj; - } - throw new IOException("Unauthorized serialization attempt " + clazz.getName()); - } - } - - public static String serializeObject(final Serializable object) { - - Preconditions.checkArgument(object != null, "object must not be null"); - - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try (final ObjectOutputStream out = SafeObjectOutputStream.create(bos)) { - out.writeObject(object); - } catch (final Exception e) { - throw new OpenSearchException("Instance {} of class {} is not serializable", e, object, object.getClass()); - } - final byte[] bytes = bos.toByteArray(); - return BaseEncoding.base64().encode(bytes); - } - - public static Serializable deserializeObject(final String string) { - - Preconditions.checkArgument(!Strings.isNullOrEmpty(string), "object must not be null or empty"); - - final byte[] bytes = BaseEncoding.base64().decode(string); - final ByteArrayInputStream bis = new ByteArrayInputStream(bytes); - try (SafeObjectInputStream in = new SafeObjectInputStream(bis)) { - return (Serializable) in.readObject(); - } catch (final Exception e) { - throw new OpenSearchException(e); - } - } - - private final static class SafeObjectInputStream extends ObjectInputStream { - - public SafeObjectInputStream(InputStream in) throws IOException { - super(in); - } - - @Override - protected Class resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException { - - Class clazz = super.resolveClass(desc); - if (isSafeClass(clazz)) { - return clazz; - } - - throw new InvalidClassException("Unauthorized deserialization attempt ", clazz.getName()); - } - } -} diff --git a/src/main/java/org/opensearch/security/support/ConfigConstants.java b/src/main/java/org/opensearch/security/support/ConfigConstants.java index 06cb1608d8..7aae47283d 100644 --- a/src/main/java/org/opensearch/security/support/ConfigConstants.java +++ b/src/main/java/org/opensearch/security/support/ConfigConstants.java @@ -374,8 +374,6 @@ public enum RolesMappingResolution { public static final String TENANCY_GLOBAL_TENANT_NAME = "global"; public static final String TENANCY_GLOBAL_TENANT_DEFAULT_NAME = ""; - public static final String USE_JDK_SERIALIZATION = SECURITY_SETTINGS_PREFIX + "use_jdk_serialization"; - // On-behalf-of endpoints settings // CS-SUPPRESS-SINGLE: RegexpSingleline get Extensions Settings public static final String EXTENSIONS_BWC_PLUGIN_MODE = "bwcPluginMode"; diff --git a/src/main/java/org/opensearch/security/support/HeaderHelper.java b/src/main/java/org/opensearch/security/support/HeaderHelper.java index 3b237f5891..4b405a54b4 100644 --- a/src/main/java/org/opensearch/security/support/HeaderHelper.java +++ b/src/main/java/org/opensearch/security/support/HeaderHelper.java @@ -27,8 +27,6 @@ package org.opensearch.security.support; import java.io.Serializable; -import java.util.Arrays; -import java.util.List; import com.google.common.base.Strings; @@ -83,7 +81,7 @@ public static Serializable deserializeSafeFromHeader(final ThreadContext context final String objectAsBase64 = getSafeFromHeader(context, headerName); if (!Strings.isNullOrEmpty(objectAsBase64)) { - return Base64Helper.deserializeObject(objectAsBase64, context.getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); + return Base64Helper.deserializeObject(objectAsBase64); } return null; @@ -92,16 +90,4 @@ public static Serializable deserializeSafeFromHeader(final ThreadContext context public static boolean isTrustedClusterRequest(final ThreadContext context) { return context.getTransient(ConfigConstants.OPENDISTRO_SECURITY_SSL_TRANSPORT_TRUSTED_CLUSTER_REQUEST) == Boolean.TRUE; } - - public static List getAllSerializedHeaderNames() { - return Arrays.asList( - ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS_HEADER, - ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, - ConfigConstants.OPENDISTRO_SECURITY_DLS_QUERY_HEADER, - ConfigConstants.OPENDISTRO_SECURITY_FLS_FIELDS_HEADER, - ConfigConstants.OPENDISTRO_SECURITY_MASKED_FIELD_HEADER, - ConfigConstants.OPENDISTRO_SECURITY_DLS_FILTER_LEVEL_QUERY_HEADER, - ConfigConstants.OPENDISTRO_SECURITY_SOURCE_FIELD_CONTEXT - ); - } } diff --git a/src/main/java/org/opensearch/security/support/SerializationFormat.java b/src/main/java/org/opensearch/security/support/SerializationFormat.java deleted file mode 100644 index 210a5cf6a5..0000000000 --- a/src/main/java/org/opensearch/security/support/SerializationFormat.java +++ /dev/null @@ -1,35 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.support; - -import org.opensearch.Version; - -public enum SerializationFormat { - /** Uses Java's native serialization system */ - JDK, - /** Uses a custom serializer built ontop of OpenSearch 2.11 */ - CustomSerializer_2_11; - - private static final Version FIRST_CUSTOM_SERIALIZATION_SUPPORTED_OS_VERSION = Version.V_2_11_0; - private static final Version CUSTOM_SERIALIZATION_NO_LONGER_SUPPORTED_OS_VERSION = Version.V_2_14_0; - - /** - * Determines the format of serialization that should be used from a version identifier - */ - public static SerializationFormat determineFormat(final Version version) { - if (version.onOrAfter(FIRST_CUSTOM_SERIALIZATION_SUPPORTED_OS_VERSION) - && version.before(CUSTOM_SERIALIZATION_NO_LONGER_SUPPORTED_OS_VERSION)) { - return SerializationFormat.CustomSerializer_2_11; - } - return SerializationFormat.JDK; - } -} diff --git a/src/main/java/org/opensearch/security/support/SourceFieldsContext.java b/src/main/java/org/opensearch/security/support/SourceFieldsContext.java index 83bbb683e9..02f0ad9226 100644 --- a/src/main/java/org/opensearch/security/support/SourceFieldsContext.java +++ b/src/main/java/org/opensearch/security/support/SourceFieldsContext.java @@ -26,18 +26,13 @@ package org.opensearch.security.support; -import java.io.IOException; import java.io.Serializable; import java.util.Arrays; -import java.util.Objects; import org.opensearch.action.get.GetRequest; import org.opensearch.action.search.SearchRequest; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.common.io.stream.Writeable; -public class SourceFieldsContext implements Serializable, Writeable { +public class SourceFieldsContext implements Serializable { private String[] includes; private String[] excludes; @@ -82,18 +77,6 @@ public SourceFieldsContext(SearchRequest request) { // } } - public SourceFieldsContext(StreamInput in) throws IOException { - includes = in.readStringArray(); - if (includes.length == 0) { - includes = null; - } - excludes = in.readStringArray(); - if (excludes.length == 0) { - excludes = null; - } - fetchSource = in.readBoolean(); - } - public SourceFieldsContext(GetRequest request) { if (request.fetchSourceContext() != null) { includes = request.fetchSourceContext().includes(); @@ -134,11 +117,4 @@ public String toString() { + fetchSource + "]"; } - - @Override - public void writeTo(StreamOutput streamOutput) throws IOException { - streamOutput.writeStringArray(Objects.requireNonNullElseGet(includes, () -> new String[] {})); - streamOutput.writeStringArray(Objects.requireNonNullElseGet(excludes, () -> new String[] {})); - streamOutput.writeBoolean(fetchSource); - } } diff --git a/src/main/java/org/opensearch/security/support/StreamableRegistry.java b/src/main/java/org/opensearch/security/support/StreamableRegistry.java deleted file mode 100644 index bfde866376..0000000000 --- a/src/main/java/org/opensearch/security/support/StreamableRegistry.java +++ /dev/null @@ -1,134 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.support; - -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.util.HashMap; -import java.util.Map; - -import com.google.common.collect.BiMap; -import com.google.common.collect.HashBiMap; - -import org.opensearch.OpenSearchException; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.common.io.stream.Writeable; - -/** - * Registry for any class that does NOT implement the Writeable interface - * and needs to be serialized over the wire. Supports registration of writer and reader via registerStreamable - * for such classes and provides methods writeTo and readFrom for objects of such registered classes. - *
- * Methods are protected and intended to be accessed from only within the package. (mostly by Base64Helper) - */ -public class StreamableRegistry { - - private static final StreamableRegistry INSTANCE = new StreamableRegistry(); - public final BiMap, Integer> classToIdMap = HashBiMap.create(); - private final Map idToEntryMap = new HashMap<>(); - - private StreamableRegistry() { - registerAllStreamables(); - } - - private static class Entry { - Writeable.Writer writer; - Writeable.Reader reader; - - Entry(Writeable.Writer writer, Writeable.Reader reader) { - this.writer = writer; - this.reader = reader; - } - } - - private Writeable.Writer getWriter(Class clazz) { - if (!classToIdMap.containsKey(clazz)) { - throw new OpenSearchException(String.format("No writer registered for class %s", clazz.getName())); - } - return idToEntryMap.get(classToIdMap.get(clazz)).writer; - } - - private Writeable.Reader getReader(int id) { - if (!idToEntryMap.containsKey(id)) { - throw new OpenSearchException(String.format("No reader registered for id %s", id)); - } - return idToEntryMap.get(id).reader; - } - - private int getId(Class clazz) { - if (!classToIdMap.containsKey(clazz)) { - throw new OpenSearchException(String.format("No writer registered for class %s", clazz.getName())); - } - return classToIdMap.get(clazz); - } - - protected boolean isStreamable(Class clazz) { - return classToIdMap.containsKey(clazz); - } - - protected void writeTo(StreamOutput out, Object object) throws IOException { - out.writeByte((byte) getId(object.getClass())); - getWriter(object.getClass()).write(out, object); - } - - protected Object readFrom(StreamInput in) throws IOException { - int id = in.readByte(); - return getReader(id).read(in); - } - - protected static StreamableRegistry getInstance() { - return INSTANCE; - } - - protected void registerStreamable(int streamableId, Class clazz, Writeable.Writer writer, Writeable.Reader reader) { - if (Writeable.class.isAssignableFrom(clazz)) { - throw new IllegalArgumentException( - String.format("%s is Writeable and should not be registered as a streamable", clazz.getName()) - ); - } - classToIdMap.put(clazz, streamableId); - idToEntryMap.put(streamableId, new Entry(writer, reader)); - } - - protected int getStreamableID(Class clazz) { - if (!isStreamable(clazz)) { - throw new OpenSearchException(String.format("class %s is in streamable registry", clazz.getName())); - } else { - return classToIdMap.get(clazz); - } - } - - /** - * Register all streamables here. - *
- * Caution - Register new streamables towards the end. Removing / reordering a registered streamable will change the typeIDs associated with the streamables - * causing a breaking change in the serialization format. - */ - private void registerAllStreamables() { - - // InetSocketAddress - this.registerStreamable(1, InetSocketAddress.class, (o, v) -> { - final InetSocketAddress inetSocketAddress = (InetSocketAddress) v; - o.writeString(inetSocketAddress.getHostString()); - o.writeByteArray(inetSocketAddress.getAddress().getAddress()); - o.writeInt(inetSocketAddress.getPort()); - }, i -> { - String host = i.readString(); - byte[] addressBytes = i.readByteArray(); - int port = i.readInt(); - return new InetSocketAddress(InetAddress.getByAddress(host, addressBytes), port); - }); - } - -} diff --git a/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java b/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java index 7be544c9cd..72d55de00f 100644 --- a/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java +++ b/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java @@ -39,7 +39,6 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -import org.opensearch.Version; import org.opensearch.action.admin.cluster.shards.ClusterSearchShardsAction; import org.opensearch.action.admin.cluster.shards.ClusterSearchShardsResponse; import org.opensearch.action.get.GetRequest; @@ -63,8 +62,6 @@ import org.opensearch.security.ssl.transport.SSLConfig; import org.opensearch.security.support.Base64Helper; import org.opensearch.security.support.ConfigConstants; -import org.opensearch.security.support.HeaderHelper; -import org.opensearch.security.support.SerializationFormat; import org.opensearch.security.user.User; import org.opensearch.threadpool.ThreadPool; import org.opensearch.transport.Transport.Connection; @@ -155,7 +152,6 @@ public void sendRequestDecorate( final boolean isDebugEnabled = log.isDebugEnabled(); - final var serializationFormat = SerializationFormat.determineFormat(connection.getVersion()); final boolean isSameNodeRequest = localNode != null && localNode.equals(connection.getNode()); try (ThreadContext.StoredContext stashedContext = getThreadContext().stashContext()) { @@ -237,38 +233,9 @@ && getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_ROL ); } - try { - if (clusterInfoHolder.getMinNodeVersion() == null || clusterInfoHolder.getMinNodeVersion().before(Version.V_2_14_0)) { - if (serializationFormat == SerializationFormat.JDK) { - Map jdkSerializedHeaders = new HashMap<>(); - HeaderHelper.getAllSerializedHeaderNames() - .stream() - .filter(k -> headerMap.get(k) != null) - .forEach(k -> jdkSerializedHeaders.put(k, Base64Helper.ensureJDKSerialized(headerMap.get(k)))); - headerMap.putAll(jdkSerializedHeaders); - } else if (serializationFormat == SerializationFormat.CustomSerializer_2_11) { - Map customSerializedHeaders = new HashMap<>(); - HeaderHelper.getAllSerializedHeaderNames() - .stream() - .filter(k -> headerMap.get(k) != null) - .forEach(k -> customSerializedHeaders.put(k, Base64Helper.ensureCustomSerialized(headerMap.get(k)))); - headerMap.putAll(customSerializedHeaders); - } - } - getThreadContext().putHeader(headerMap); - } catch (IllegalArgumentException iae) { - log.debug("Failed to add headers information onto on thread context", iae); - } + getThreadContext().putHeader(headerMap); - ensureCorrectHeaders( - remoteAddress0, - user0, - origin0, - injectedUserString, - injectedRolesString, - isSameNodeRequest, - serializationFormat - ); + ensureCorrectHeaders(remoteAddress0, user0, origin0, injectedUserString, injectedRolesString, isSameNodeRequest); if (actionTraceEnabled.get()) { getThreadContext().putHeader( @@ -295,8 +262,7 @@ private void ensureCorrectHeaders( final String origin, final String injectedUserString, final String injectedRolesString, - final boolean isSameNodeRequest, - final SerializationFormat format + final boolean isSameNodeRequest ) { // keep original address @@ -334,11 +300,10 @@ && getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN_HEADE getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_USER, injectedUserString); } } else { - final var useJDKSerialization = format == SerializationFormat.JDK; if (transportAddress != null) { getThreadContext().putHeader( ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS_HEADER, - Base64Helper.serializeObject(transportAddress.address(), useJDKSerialization) + Base64Helper.serializeObject(transportAddress.address()) ); } @@ -346,10 +311,7 @@ && getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN_HEADE if (userHeader == null) { // put as headers for other requests if (origUser != null) { - getThreadContext().putHeader( - ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, - Base64Helper.serializeObject(origUser, useJDKSerialization) - ); + getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, Base64Helper.serializeObject(origUser)); } else if (StringUtils.isNotEmpty(injectedRolesString)) { getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_ROLES_HEADER, injectedRolesString); } else if (StringUtils.isNotEmpty(injectedUserString)) { diff --git a/src/main/java/org/opensearch/security/transport/SecurityRequestHandler.java b/src/main/java/org/opensearch/security/transport/SecurityRequestHandler.java index 18c0c21282..45aa399a84 100644 --- a/src/main/java/org/opensearch/security/transport/SecurityRequestHandler.java +++ b/src/main/java/org/opensearch/security/transport/SecurityRequestHandler.java @@ -107,8 +107,6 @@ protected void messageReceivedDecorate( resolvedActionClass = ((ConcreteShardRequest) request).getRequest().getClass().getSimpleName(); } - final boolean useJDKSerialization = getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION); - String initialActionClassValue = getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_INITIAL_ACTION_CLASS_HEADER); final ThreadContext.StoredContext sgContext = getThreadContext().newStoredContext(false); @@ -183,7 +181,7 @@ protected void messageReceivedDecorate( } else { getThreadContext().putTransient( ConfigConstants.OPENDISTRO_SECURITY_USER, - Objects.requireNonNull((User) Base64Helper.deserializeObject(userHeader, useJDKSerialization)) + Objects.requireNonNull((User) Base64Helper.deserializeObject(userHeader)) ); } @@ -192,7 +190,7 @@ protected void messageReceivedDecorate( if (!Strings.isNullOrEmpty(originalRemoteAddress)) { getThreadContext().putTransient( ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, - new TransportAddress((InetSocketAddress) Base64Helper.deserializeObject(originalRemoteAddress, useJDKSerialization)) + new TransportAddress((InetSocketAddress) Base64Helper.deserializeObject(originalRemoteAddress)) ); } else { getThreadContext().putTransient(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS, request.remoteAddress()); diff --git a/src/main/java/org/opensearch/security/user/User.java b/src/main/java/org/opensearch/security/user/User.java index 190729623d..40923293f4 100644 --- a/src/main/java/org/opensearch/security/user/User.java +++ b/src/main/java/org/opensearch/security/user/User.java @@ -26,9 +26,7 @@ package org.opensearch.security.user; -import java.io.IOException; import java.io.Serializable; -import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -38,17 +36,13 @@ import com.google.common.collect.Lists; -import org.opensearch.core.common.io.stream.StreamInput; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.common.io.stream.Writeable; - /** * A authenticated user and attributes associated to them (like roles, tenant, custom attributes) *

* Do not subclass from this class! * */ -public class User implements Serializable, Writeable, CustomAttributesAware { +public class User implements Serializable, CustomAttributesAware { public static final User ANONYMOUS = new User( "opendistro_security_anonymous", @@ -78,18 +72,6 @@ public class User implements Serializable, Writeable, CustomAttributesAware { private Map attributes = Collections.synchronizedMap(new HashMap<>()); private boolean isInjected = false; - public User(final StreamInput in) throws IOException { - super(); - name = in.readString(); - roles.addAll(in.readList(StreamInput::readString)); - requestedTenant = in.readString(); - if (requestedTenant.isEmpty()) { - requestedTenant = null; - } - attributes = Collections.synchronizedMap(in.readMap(StreamInput::readString, StreamInput::readString)); - securityRoles.addAll(in.readList(StreamInput::readString)); - } - /** * Create a new authenticated user * @@ -254,15 +236,6 @@ public final void copyRolesFrom(final User user) { } } - @Override - public void writeTo(StreamOutput out) throws IOException { - out.writeString(name); - out.writeStringCollection(new ArrayList(roles)); - out.writeString(requestedTenant == null ? "" : requestedTenant); - out.writeMap(attributes, StreamOutput::writeString, StreamOutput::writeString); - out.writeStringCollection(securityRoles == null ? Collections.emptyList() : new ArrayList(securityRoles)); - } - /** * Get the custom attributes associated with this user * diff --git a/src/test/java/org/opensearch/security/support/Base64CustomHelperTest.java b/src/test/java/org/opensearch/security/support/Base64CustomHelperTest.java deleted file mode 100644 index a5151be9fb..0000000000 --- a/src/test/java/org/opensearch/security/support/Base64CustomHelperTest.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.support; - -import java.io.Serializable; -import java.net.InetSocketAddress; -import java.time.ZonedDateTime; -import java.util.ArrayList; -import java.util.HashMap; - -import org.junit.Assert; -import org.junit.Test; - -import org.opensearch.OpenSearchException; -import org.opensearch.action.search.SearchRequest; -import org.opensearch.core.common.io.stream.StreamOutput; -import org.opensearch.core.common.io.stream.Writeable; -import org.opensearch.security.auth.UserInjector; -import org.opensearch.security.user.AuthCredentials; -import org.opensearch.security.user.User; - -import com.amazon.dlic.auth.ldap.LdapUser; -import org.ldaptive.LdapEntry; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; -import static org.opensearch.security.support.Base64CustomHelper.deserializeObject; -import static org.opensearch.security.support.Base64CustomHelper.serializeObject; - -public class Base64CustomHelperTest { - - private static final class NotSafeStreamable implements Serializable { - private static final long serialVersionUID = 5135559266828470092L; - } - - private static final class NotSafeWriteable implements Writeable, Serializable { - @Override - public void writeTo(StreamOutput out) { - - } - } - - private static Serializable ds(Serializable s) { - return deserializeObject(serializeObject(s)); - } - - @Test - public void testString() { - String string = "string"; - assertThat(ds(string), is(string)); - } - - @Test - public void testInteger() { - Integer integer = 0; - assertThat(ds(integer), is(integer)); - } - - @Test - public void testDouble() { - Double number = 0.; - assertThat(ds(number), is(number)); - } - - @Test - public void testInetSocketAddress() { - InetSocketAddress inetSocketAddress = new InetSocketAddress(0); - assertThat(ds(inetSocketAddress), is(inetSocketAddress)); - } - - @Test - public void testUser() { - User user = new User("user"); - assertThat(ds(user), is(user)); - } - - @Test - public void testSourceFieldsContext() { - SourceFieldsContext sourceFieldsContext = new SourceFieldsContext(new SearchRequest("")); - assertThat(ds(sourceFieldsContext).toString(), is(sourceFieldsContext.toString())); - } - - @Test - public void testHashMap() { - HashMap map = new HashMap<>() { - { - put("key", "value"); - } - }; - assertThat(ds(map), is(map)); - } - - @Test - public void testArrayList() { - ArrayList list = new ArrayList<>() { - { - add("value"); - } - }; - assertThat(ds(list), is(list)); - } - - @Test - public void testLdapUser() { - LdapUser ldapUser = new LdapUser( - "username", - "originalusername", - new LdapEntry("dn"), - new AuthCredentials("originalusername", "12345"), - 34, - WildcardMatcher.ANY - ); - assertThat(ds(ldapUser), is(ldapUser)); - } - - @Test - public void testGetWriteableClassID() { - // a need to make a change in this test signifies a breaking change in security plugin's custom serialization - // format - assertThat(Base64CustomHelper.getWriteableClassID(User.class), is(Integer.valueOf(1))); - assertThat(Base64CustomHelper.getWriteableClassID(LdapUser.class), is(Integer.valueOf(2))); - assertThat(Base64CustomHelper.getWriteableClassID(UserInjector.InjectedUser.class), is(Integer.valueOf(3))); - assertThat(Base64CustomHelper.getWriteableClassID(SourceFieldsContext.class), is(Integer.valueOf(4))); - } - - @Test - public void testInjectedUser() { - UserInjector.InjectedUser injectedUser = new UserInjector.InjectedUser("username"); - - // for custom serialization, we expect InjectedUser to be returned on deserialization - UserInjector.InjectedUser deserializedInjecteduser = (UserInjector.InjectedUser) ds(injectedUser); - assertThat(deserializedInjecteduser, is(injectedUser)); - Assert.assertTrue(deserializedInjecteduser.isInjected()); - } - - @Test(expected = OpenSearchException.class) - public void testNotSafeStreamable() { - Base64JDKHelper.serializeObject(new NotSafeStreamable()); - } - - @Test(expected = OpenSearchException.class) - public void testNotSafeWriteable() { - Base64JDKHelper.serializeObject(new NotSafeWriteable()); - } - - @Test(expected = OpenSearchException.class) - public void testNotSafeGeneric() { - HashMap map = new HashMap<>(); - map.put(1, ZonedDateTime.now()); - map.put(2, ZonedDateTime.now()); - Base64JDKHelper.serializeObject(map); - } - -} diff --git a/src/test/java/org/opensearch/security/support/Base64HelperTest.java b/src/test/java/org/opensearch/security/support/Base64HelperTest.java index 7c7e68b342..b350a6b543 100644 --- a/src/test/java/org/opensearch/security/support/Base64HelperTest.java +++ b/src/test/java/org/opensearch/security/support/Base64HelperTest.java @@ -10,26 +10,136 @@ */ package org.opensearch.security.support; +import java.io.ByteArrayOutputStream; +import java.io.ObjectOutputStream; import java.io.Serializable; +import java.net.InetSocketAddress; +import java.util.ArrayList; import java.util.HashMap; import java.util.stream.IntStream; +import com.google.common.io.BaseEncoding; +import org.junit.Assert; import org.junit.Test; +import org.opensearch.OpenSearchException; +import org.opensearch.action.search.SearchRequest; +import org.opensearch.security.auth.UserInjector; +import org.opensearch.security.user.AuthCredentials; +import org.opensearch.security.user.User; + +import com.amazon.dlic.auth.ldap.LdapUser; +import org.ldaptive.LdapEntry; + import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.closeTo; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; -import static org.opensearch.security.support.Base64Helper.deserializeObject; -import static org.opensearch.security.support.Base64Helper.serializeObject; +import static org.junit.Assert.assertThrows; public class Base64HelperTest { - private static Serializable dsJDK(Serializable s) { - return deserializeObject(serializeObject(s, true), true); + private static final class NotSafeSerializable implements Serializable { + private static final long serialVersionUID = 5135559266828470092L; } private static Serializable ds(Serializable s) { - return deserializeObject(serializeObject(s)); + return Base64Helper.deserializeObject(Base64Helper.serializeObject(s)); + } + + @Test + public void testString() { + String string = "string"; + assertThat(ds(string), is(string)); + } + + @Test + public void testInteger() { + Integer integer = 0; + assertThat(ds(integer), is(integer)); + } + + @Test + public void testDouble() { + Double number = 0.0; + assertThat(ds(number), is(number)); + } + + @Test + public void testInetSocketAddress() { + InetSocketAddress inetSocketAddress = new InetSocketAddress(0); + assertThat(ds(inetSocketAddress), is(inetSocketAddress)); + } + + @Test + public void testUser() { + User user = new User("user"); + assertThat(ds(user), is(user)); + } + + @Test + public void testSourceFieldsContext() { + SourceFieldsContext sourceFieldsContext = new SourceFieldsContext(new SearchRequest("")); + assertThat(ds(sourceFieldsContext).toString(), is(sourceFieldsContext.toString())); + } + + @Test + public void testHashMap() { + HashMap map = new HashMap<>(); + map.put("key", "value"); + assertThat(ds(map), is(map)); + } + + @Test + public void testArrayList() { + ArrayList list = new ArrayList<>(); + list.add("value"); + assertThat(ds(list), is(list)); + } + + @Test + public void notSafeSerializable() { + final OpenSearchException exception = assertThrows( + OpenSearchException.class, + () -> Base64Helper.serializeObject(new NotSafeSerializable()) + ); + assertThat(exception.getMessage(), containsString("NotSafeSerializable is not serializable")); + } + + @Test + public void notSafeDeserializable() throws Exception { + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); + try (final ObjectOutputStream out = new ObjectOutputStream(bos)) { + out.writeObject(new NotSafeSerializable()); + } + final OpenSearchException exception = assertThrows( + OpenSearchException.class, + () -> Base64Helper.deserializeObject(BaseEncoding.base64().encode(bos.toByteArray())) + ); + assertThat(exception.getMessage(), containsString("Unauthorized deserialization attempt")); + } + + @Test + public void testLdapUser() { + LdapUser ldapUser = new LdapUser( + "username", + "originalusername", + new LdapEntry("dn"), + new AuthCredentials("originalusername", "12345"), + 34, + WildcardMatcher.ANY + ); + assertThat(ds(ldapUser), is(ldapUser)); + } + + @Test + public void testInjectedUser() { + UserInjector.InjectedUser injectedUser = new UserInjector.InjectedUser("username"); + + // we expect to get User object when deserializing InjectedUser via JDK serialization + User user = new User("username"); + User deserializedUser = (User) ds(injectedUser); + assertThat(deserializedUser, is(user)); + Assert.assertTrue(deserializedUser.isInjected()); } /** @@ -41,25 +151,6 @@ private static Serializable ds(Serializable s) { public void testSerde() { String test = "string"; assertThat(ds(test), is(test)); - assertThat(dsJDK(test), is(test)); - } - - @Test - public void testEnsureJDKSerialized() { - String test = "string"; - String jdkSerialized = Base64Helper.serializeObject(test, true); - String customSerialized = Base64Helper.serializeObject(test, false); - assertThat(Base64Helper.ensureJDKSerialized(jdkSerialized), is(jdkSerialized)); - assertThat(Base64Helper.ensureJDKSerialized(customSerialized), is(jdkSerialized)); - } - - @Test - public void testEnsureCustomSerialized() { - String test = "string"; - String jdkSerialized = Base64Helper.serializeObject(test, true); - String customSerialized = Base64Helper.serializeObject(test, false); - assertThat(Base64Helper.ensureCustomSerialized(jdkSerialized), is(customSerialized)); - assertThat(Base64Helper.ensureCustomSerialized(customSerialized), is(customSerialized)); } @Test @@ -69,14 +160,8 @@ public void testDuplicatedItemSizes() { IntStream.range(0, 100).forEach(i -> { hm.put("c" + i, "cvalue" + i); }); IntStream.range(0, 100).forEach(i -> { largeObject.put("b" + i, hm); }); - final var jdkSerialized = Base64Helper.serializeObject(largeObject, true); - final var customSerialized = Base64Helper.serializeObject(largeObject, false); - final var customSerializedOnlyHashMap = Base64Helper.serializeObject(hm, false); + final var jdkSerialized = Base64Helper.serializeObject(largeObject); assertThat(jdkSerialized.length(), is(3832)); - // The custom serializer is ~50x larger than the jdk serialized version - assertThat(customSerialized.length(), is(184792)); - // Show that the majority of the size of the custom serialized large object is the map duplicated ~100 times - assertThat((double) customSerializedOnlyHashMap.length(), closeTo(customSerialized.length() / 100, 70d)); } } diff --git a/src/test/java/org/opensearch/security/support/Base64JDKHelperTest.java b/src/test/java/org/opensearch/security/support/Base64JDKHelperTest.java deleted file mode 100644 index 8737f5b6ac..0000000000 --- a/src/test/java/org/opensearch/security/support/Base64JDKHelperTest.java +++ /dev/null @@ -1,143 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.support; - -import java.io.ByteArrayOutputStream; -import java.io.ObjectOutputStream; -import java.io.Serializable; -import java.net.InetSocketAddress; -import java.util.ArrayList; -import java.util.HashMap; - -import com.google.common.io.BaseEncoding; -import org.junit.Assert; -import org.junit.Test; - -import org.opensearch.OpenSearchException; -import org.opensearch.action.search.SearchRequest; -import org.opensearch.security.auth.UserInjector; -import org.opensearch.security.user.AuthCredentials; -import org.opensearch.security.user.User; - -import com.amazon.dlic.auth.ldap.LdapUser; -import org.ldaptive.LdapEntry; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThrows; - -public class Base64JDKHelperTest { - private static final class NotSafeSerializable implements Serializable { - private static final long serialVersionUID = 5135559266828470092L; - } - - private static Serializable ds(Serializable s) { - return Base64JDKHelper.deserializeObject(Base64JDKHelper.serializeObject(s)); - } - - @Test - public void testString() { - String string = "string"; - assertThat(ds(string), is(string)); - } - - @Test - public void testInteger() { - Integer integer = 0; - assertThat(ds(integer), is(integer)); - } - - @Test - public void testDouble() { - Double number = 0.0; - assertThat(ds(number), is(number)); - } - - @Test - public void testInetSocketAddress() { - InetSocketAddress inetSocketAddress = new InetSocketAddress(0); - assertThat(ds(inetSocketAddress), is(inetSocketAddress)); - } - - @Test - public void testUser() { - User user = new User("user"); - assertThat(ds(user), is(user)); - } - - @Test - public void testSourceFieldsContext() { - SourceFieldsContext sourceFieldsContext = new SourceFieldsContext(new SearchRequest("")); - assertThat(ds(sourceFieldsContext).toString(), is(sourceFieldsContext.toString())); - } - - @Test - public void testHashMap() { - HashMap map = new HashMap<>(); - map.put("key", "value"); - assertThat(ds(map), is(map)); - } - - @Test - public void testArrayList() { - ArrayList list = new ArrayList<>(); - list.add("value"); - assertThat(ds(list), is(list)); - } - - @Test - public void notSafeSerializable() { - final OpenSearchException exception = assertThrows( - OpenSearchException.class, - () -> Base64JDKHelper.serializeObject(new NotSafeSerializable()) - ); - assertThat(exception.getMessage(), containsString("NotSafeSerializable is not serializable")); - } - - @Test - public void notSafeDeserializable() throws Exception { - final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try (final ObjectOutputStream out = new ObjectOutputStream(bos)) { - out.writeObject(new NotSafeSerializable()); - } - final OpenSearchException exception = assertThrows( - OpenSearchException.class, - () -> Base64JDKHelper.deserializeObject(BaseEncoding.base64().encode(bos.toByteArray())) - ); - assertThat(exception.getMessage(), containsString("Unauthorized deserialization attempt")); - } - - @Test - public void testLdapUser() { - LdapUser ldapUser = new LdapUser( - "username", - "originalusername", - new LdapEntry("dn"), - new AuthCredentials("originalusername", "12345"), - 34, - WildcardMatcher.ANY - ); - assertThat(ds(ldapUser), is(ldapUser)); - } - - @Test - public void testInjectedUser() { - UserInjector.InjectedUser injectedUser = new UserInjector.InjectedUser("username"); - - // we expect to get User object when deserializing InjectedUser via JDK serialization - User user = new User("username"); - User deserializedUser = (User) ds(injectedUser); - assertThat(deserializedUser, is(user)); - Assert.assertTrue(deserializedUser.isInjected()); - } -} diff --git a/src/test/java/org/opensearch/security/support/StreamableRegistryTest.java b/src/test/java/org/opensearch/security/support/StreamableRegistryTest.java deleted file mode 100644 index 9d5da3930a..0000000000 --- a/src/test/java/org/opensearch/security/support/StreamableRegistryTest.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - * Modifications Copyright OpenSearch Contributors. See - * GitHub history for details. - */ - -package org.opensearch.security.support; - -import java.net.InetSocketAddress; - -import org.junit.Assert; -import org.junit.Test; - -import org.opensearch.OpenSearchException; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.is; - -public class StreamableRegistryTest { - - StreamableRegistry streamableRegistry = StreamableRegistry.getInstance(); - - @Test - public void testStreamableTypeIDs() { - assertThat(streamableRegistry.getStreamableID(InetSocketAddress.class), is(1)); - Assert.assertThrows(OpenSearchException.class, () -> streamableRegistry.getStreamableID(String.class)); - } -} diff --git a/src/test/java/org/opensearch/security/transport/SecurityInterceptorTests.java b/src/test/java/org/opensearch/security/transport/SecurityInterceptorTests.java index d12fafb247..2443abb7e8 100644 --- a/src/test/java/org/opensearch/security/transport/SecurityInterceptorTests.java +++ b/src/test/java/org/opensearch/security/transport/SecurityInterceptorTests.java @@ -219,27 +219,12 @@ public void sendRequest( TransportResponseHandler handler ) { String serializedUserHeader = threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER); - User deserializedUser = (User) Base64Helper.deserializeObject(serializedUserHeader, true); + User deserializedUser = (User) Base64Helper.deserializeObject(serializedUserHeader); assertThat(deserializedUser, is(user)); senderLatch.get().countDown(); } }; - customSerializedSender = new AsyncSender() { - @Override - public void sendRequest( - Connection connection, - String action, - TransportRequest request, - TransportRequestOptions options, - TransportResponseHandler handler - ) { - String serializedUserHeader = threadPool.getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER); - assertThat(serializedUserHeader, is(Base64Helper.serializeObject(user, false))); - senderLatch.get().countDown(); - } - }; - sender = new AsyncSender() { @Override public void sendRequest( @@ -332,7 +317,7 @@ public void testSendRequestDecorateRemoteConnection() { @Test public void testSendRequestDecorateRemoteConnectionUsesJDKSerialization() { - threadPool.getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, Base64Helper.serializeObject(user, false)); + threadPool.getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, Base64Helper.serializeObject(user)); completableRequestDecorateWithPreviouslyPopulatedHeaders( jdkSerializedSender, connection3, @@ -344,20 +329,6 @@ public void testSendRequestDecorateRemoteConnectionUsesJDKSerialization() { ); } - @Test - public void testSendRequestDecorateRemoteConnectionUsesCustomSerialization() { - threadPool.getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, Base64Helper.serializeObject(user, true)); - completableRequestDecorateWithPreviouslyPopulatedHeaders( - customSerializedSender, - connection5, - action, - request, - options, - handler, - localNode - ); - } - @Test public void testSendNoOriginNodeCausesSerialization() { diff --git a/src/test/java/org/opensearch/security/transport/SecuritySSLRequestHandlerTests.java b/src/test/java/org/opensearch/security/transport/SecuritySSLRequestHandlerTests.java deleted file mode 100644 index c63c8d26ae..0000000000 --- a/src/test/java/org/opensearch/security/transport/SecuritySSLRequestHandlerTests.java +++ /dev/null @@ -1,198 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - * - * The OpenSearch Contributors require contributions made to - * this file be licensed under the Apache-2.0 license or a - * compatible open source license. - * - */ -package org.opensearch.security.transport; - -import java.io.IOException; - -import org.junit.Assert; -import org.junit.Before; -import org.junit.Test; - -import org.opensearch.Version; -import org.opensearch.common.settings.Settings; -import org.opensearch.core.transport.TransportResponse; -import org.opensearch.security.ssl.SslExceptionHandler; -import org.opensearch.security.ssl.transport.PrincipalExtractor; -import org.opensearch.security.ssl.transport.SSLConfig; -import org.opensearch.security.ssl.transport.SecuritySSLRequestHandler; -import org.opensearch.security.support.ConfigConstants; -import org.opensearch.tasks.Task; -import org.opensearch.threadpool.ThreadPool; -import org.opensearch.transport.TransportChannel; -import org.opensearch.transport.TransportRequest; -import org.opensearch.transport.TransportRequestHandler; - -import org.mockito.ArgumentMatchers; -import org.mockito.InOrder; -import org.mockito.Mock; - -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.doNothing; -import static org.mockito.Mockito.inOrder; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.when; - -public class SecuritySSLRequestHandlerTests { - - @Mock - TransportRequestHandler actualHandler; - @Mock - SSLConfig sslConfig; - ThreadPool threadPool; - SslExceptionHandler sslExceptionHandler; - Settings settings; - SecuritySSLRequestHandler securitySSLRequestHandler; - String testAction; - - @Mock - private PrincipalExtractor principalExtractor; - - @Before - public void setUp() { - settings = Settings.builder() - .put("node.name", SecurityInterceptorTests.class.getSimpleName()) - .put("request.headers.default", "1") - .build(); - threadPool = new ThreadPool(settings); - testAction = "test_action"; - sslExceptionHandler = mock(SslExceptionHandler.class); - securitySSLRequestHandler = new SecuritySSLRequestHandler<>( - testAction, - actualHandler, - threadPool, - principalExtractor, - sslConfig, - sslExceptionHandler - ); - doNothing().when(sslExceptionHandler) - .logError(any(Exception.class), any(TransportRequest.class), any(String.class), any(Task.class), anyInt()); - } - - @Test - public void testUseJDKSerializationHeaderIsSetOnMessageReceived() throws Exception { - TransportRequest transportRequest = mock(TransportRequest.class); - TransportChannel transportChannel = mock(TransportChannel.class); - Task task = mock(Task.class); - doNothing().when(transportChannel).sendResponse(ArgumentMatchers.any(Exception.class)); - when(transportChannel.getVersion()).thenReturn(Version.V_2_10_0); - when(transportChannel.getChannelType()).thenReturn("transport"); - - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, transportChannel, task)); - Assert.assertTrue(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - threadPool.getThreadContext().stashContext(); - when(transportChannel.getVersion()).thenReturn(Version.V_2_11_0); - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, transportChannel, task)); - Assert.assertFalse(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - threadPool.getThreadContext().stashContext(); - when(transportChannel.getVersion()).thenReturn(Version.V_2_13_0); - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, transportChannel, task)); - Assert.assertFalse(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - threadPool.getThreadContext().stashContext(); - when(transportChannel.getVersion()).thenReturn(Version.V_2_14_0); - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, transportChannel, task)); - Assert.assertTrue(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - threadPool.getThreadContext().stashContext(); - when(transportChannel.getVersion()).thenReturn(Version.V_3_0_0); - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, transportChannel, task)); - Assert.assertTrue(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - } - - @Test - public void testUseJDKSerializationHeaderIsSetWithWrapperChannel() throws Exception { - TransportRequest transportRequest = mock(TransportRequest.class); - TransportChannel transportChannel = mock(TransportChannel.class); - TransportChannel wrappedChannel = new WrappedTransportChannel(transportChannel); - Task task = mock(Task.class); - doNothing().when(transportChannel).sendResponse(ArgumentMatchers.any(Exception.class)); - when(transportChannel.getVersion()).thenReturn(Version.V_2_10_0); - when(transportChannel.getChannelType()).thenReturn("other"); - - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, wrappedChannel, task)); - Assert.assertTrue(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - threadPool.getThreadContext().stashContext(); - when(transportChannel.getVersion()).thenReturn(Version.V_2_11_0); - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, wrappedChannel, task)); - Assert.assertFalse(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - threadPool.getThreadContext().stashContext(); - when(transportChannel.getVersion()).thenReturn(Version.V_2_13_0); - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, wrappedChannel, task)); - Assert.assertFalse(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - threadPool.getThreadContext().stashContext(); - when(transportChannel.getVersion()).thenReturn(Version.V_2_14_0); - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, wrappedChannel, task)); - Assert.assertTrue(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - threadPool.getThreadContext().stashContext(); - when(transportChannel.getVersion()).thenReturn(Version.V_3_0_0); - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, wrappedChannel, task)); - Assert.assertTrue(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - } - - @Test - public void testUseJDKSerializationHeaderIsSetAfterGetInnerChannel() throws Exception { - TransportRequest transportRequest = mock(TransportRequest.class); - TransportChannel transportChannel = mock(TransportChannel.class); - WrappedTransportChannel wrappedChannel = mock(WrappedTransportChannel.class); - Task task = mock(Task.class); - when(wrappedChannel.getInnerChannel()).thenReturn(transportChannel); - when(wrappedChannel.getChannelType()).thenReturn("other"); - doNothing().when(transportChannel).sendResponse(ArgumentMatchers.any(Exception.class)); - when(transportChannel.getVersion()).thenReturn(Version.V_2_10_0); - - Assert.assertThrows(Exception.class, () -> securitySSLRequestHandler.messageReceived(transportRequest, wrappedChannel, task)); - Assert.assertTrue(threadPool.getThreadContext().getTransient(ConfigConstants.USE_JDK_SERIALIZATION)); - - InOrder inOrder = inOrder(wrappedChannel, transportChannel); - - inOrder.verify(wrappedChannel).getInnerChannel(); - inOrder.verify(transportChannel).getVersion(); - } - - public class WrappedTransportChannel implements TransportChannel { - - private TransportChannel inner; - - public WrappedTransportChannel(TransportChannel inner) { - this.inner = inner; - } - - @Override - public String getProfileName() { - return "WrappedTransportChannelProfileName"; - } - - public TransportChannel getInnerChannel() { - return this.inner; - } - - @Override - public void sendResponse(TransportResponse response) throws IOException { - inner.sendResponse(response); - } - - @Override - public void sendResponse(Exception e) throws IOException { - - } - - @Override - public String getChannelType() { - return "WrappedTransportChannelType"; - } - } -}