diff --git a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java index 54b5cc8475..2f5c8494cd 100644 --- a/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java +++ b/src/main/java/org/opensearch/security/OpenSearchSecurityPlugin.java @@ -206,6 +206,7 @@ public final class OpenSearchSecurityPlugin extends OpenSearchSecuritySSLPlugin private volatile DlsFlsRequestValve dlsFlsValve = null; private volatile Salt salt; private volatile OpensearchDynamicSetting transportPassiveAuthSetting; + private final ClusterInfoHolder cih = new ClusterInfoHolder(); public static boolean isActionTraceEnabled() { return actionTrace.isTraceEnabled(); @@ -453,7 +454,7 @@ public List getRestHandlers(Settings settings, RestController restC handlers.addAll(super.getRestHandlers(settings, restController, clusterSettings, indexScopedSettings, settingsFilter, indexNameExpressionResolver, nodesInCluster)); if(!SSLConfig.isSslOnlyMode()) { - handlers.add(new SecurityInfoAction(settings, restController, Objects.requireNonNull(evaluator), Objects.requireNonNull(threadPool))); + handlers.add(new SecurityInfoAction(settings, restController, Objects.requireNonNull(evaluator), Objects.requireNonNull(threadPool), this.cih)); handlers.add(new SecurityHealthAction(settings, restController, Objects.requireNonNull(backendRegistry))); handlers.add(new SecuritySSLCertsInfoAction(settings, restController, sks, Objects.requireNonNull(threadPool), Objects.requireNonNull(adminDns))); handlers.add(new DashboardsInfoAction(settings, restController, Objects.requireNonNull(evaluator), Objects.requireNonNull(threadPool))); @@ -752,12 +753,11 @@ public Collection createComponents(Client localClient, ClusterService cl //Register opensearch dynamic settings transportPassiveAuthSetting.registerClusterSettingsChangeListener(clusterService.getClusterSettings()); - final ClusterInfoHolder cih = new ClusterInfoHolder(); - this.cs.addListener(cih); + this.cs.addListener(this.cih); this.salt = Salt.from(settings); final IndexNameExpressionResolver resolver = new IndexNameExpressionResolver(threadPool.getThreadContext()); - irr = new IndexResolverReplacer(resolver, clusterService, cih); + irr = new IndexResolverReplacer(resolver, clusterService, this.cih); final String DEFAULT_INTERCLUSTER_REQUEST_EVALUATOR_CLASS = DefaultInterClusterRequestEvaluator.class.getName(); InterClusterRequestEvaluator interClusterRequestEvaluator = new DefaultInterClusterRequestEvaluator(settings); @@ -795,9 +795,9 @@ public Collection createComponents(Client localClient, ClusterService cl // DLS-FLS is enabled if not client and not disabled and not SSL only. final boolean dlsFlsEnabled = !SSLConfig.isSslOnlyMode(); evaluator = new PrivilegesEvaluator(clusterService, threadPool, cr, resolver, auditLog, - settings, privilegesInterceptor, cih, irr, dlsFlsEnabled); + settings, privilegesInterceptor, this.cih, irr, dlsFlsEnabled); - sf = new SecurityFilter(localClient, settings, evaluator, adminDns, dlsFlsValve, auditLog, threadPool, cs, compatConfig, irr, backendRegistry); + sf = new SecurityFilter(localClient, settings, evaluator, adminDns, dlsFlsValve, auditLog, threadPool, cs, compatConfig, irr, backendRegistry, this.cih); final String principalExtractorClass = settings.get(SSLConfigConstants.SECURITY_SSL_TRANSPORT_PRINCIPAL_EXTRACTOR_CLASS, null); @@ -810,7 +810,7 @@ public Collection createComponents(Client localClient, ClusterService cl securityRestHandler = new SecurityRestFilter(backendRegistry, auditLog, threadPool, principalExtractor, settings, configPath, compatConfig); - final DynamicConfigFactory dcf = new DynamicConfigFactory(cr, settings, configPath, localClient, threadPool, cih); + final DynamicConfigFactory dcf = new DynamicConfigFactory(cr, settings, configPath, localClient, threadPool, this.cih); dcf.registerDCFListener(backendRegistry); dcf.registerDCFListener(compatConfig); dcf.registerDCFListener(irr); @@ -825,7 +825,7 @@ public Collection createComponents(Client localClient, ClusterService cl cr.setDynamicConfigFactory(dcf); si = new SecurityInterceptor(settings, threadPool, backendRegistry, auditLog, principalExtractor, - interClusterRequestEvaluator, cs, Objects.requireNonNull(sslExceptionHandler), Objects.requireNonNull(cih), SSLConfig); + interClusterRequestEvaluator, cs, Objects.requireNonNull(sslExceptionHandler), Objects.requireNonNull(this.cih), SSLConfig); components.add(principalExtractor); // NOTE: We need to create DefaultInterClusterRequestEvaluator before creating ConfigurationRepository since the latter requires security index to be accessible which means diff --git a/src/main/java/org/opensearch/security/configuration/ClusterInfoHolder.java b/src/main/java/org/opensearch/security/configuration/ClusterInfoHolder.java index c2ba9a2470..b55347ba65 100644 --- a/src/main/java/org/opensearch/security/configuration/ClusterInfoHolder.java +++ b/src/main/java/org/opensearch/security/configuration/ClusterInfoHolder.java @@ -36,6 +36,7 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import org.opensearch.LegacyESVersion; +import org.opensearch.Version; import org.opensearch.cluster.ClusterChangedEvent; import org.opensearch.cluster.ClusterState; import org.opensearch.cluster.ClusterStateListener; @@ -49,6 +50,8 @@ public class ClusterInfoHolder implements ClusterStateListener { protected final Logger log = LogManager.getLogger(this.getClass()); private volatile Boolean has6xNodes = null; private volatile Boolean has6xIndices = null; + + private volatile Boolean hasOdfeNodes = null; private volatile DiscoveryNodes nodes = null; private volatile Boolean isLocalNodeElectedMaster = null; private volatile boolean initialized; @@ -56,6 +59,13 @@ public class ClusterInfoHolder implements ClusterStateListener { @Override public void clusterChanged(ClusterChangedEvent event) { final boolean isTraceEnabled = log.isTraceEnabled(); + if(hasOdfeNodes == null || event.nodesChanged()) { + hasOdfeNodes = Boolean.valueOf(clusterHasOdfeNodes(event.state())); + if (isTraceEnabled) { + log.trace("hasOdfeNodes: {}", hasOdfeNodes); + } + } + if(has6xNodes == null || event.nodesChanged()) { has6xNodes = Boolean.valueOf(clusterHas6xNodes(event.state())); if (isTraceEnabled) { @@ -91,6 +101,10 @@ public Boolean getHas6xIndices() { return has6xIndices; } + public Boolean getHasOdfeNodes() { + return hasOdfeNodes; + } + public Boolean isLocalNodeElectedMaster() { return isLocalNodeElectedMaster; } @@ -124,4 +138,8 @@ private static boolean clusterHas6xIndices(ClusterState state) { } return false; } + + private static boolean clusterHasOdfeNodes(ClusterState state) { + return state.nodes().getMinNodeVersion().before(Version.V_1_0_0); + } } diff --git a/src/main/java/org/opensearch/security/filter/SecurityFilter.java b/src/main/java/org/opensearch/security/filter/SecurityFilter.java index 4bc5bcc4e9..ca8bebbeee 100644 --- a/src/main/java/org/opensearch/security/filter/SecurityFilter.java +++ b/src/main/java/org/opensearch/security/filter/SecurityFilter.java @@ -31,11 +31,15 @@ package org.opensearch.security.filter; import java.util.Collections; +import java.util.Optional; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; +import org.apache.kafka.common.Cluster; +import org.opensearch.Version; import org.opensearch.security.auth.RolesInjector; +import org.opensearch.security.configuration.ClusterInfoHolder; import org.opensearch.security.resolver.IndexResolverReplacer; import org.opensearch.security.support.WildcardMatcher; import com.google.common.annotations.VisibleForTesting; @@ -94,6 +98,7 @@ import org.opensearch.threadpool.ThreadPool; import org.opensearch.security.support.Base64Helper; +import org.opensearch.security.support.Base64Helper.PackageBehavior; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.HeaderHelper; import org.opensearch.security.support.SourceFieldsContext; @@ -118,9 +123,11 @@ public class SecurityFilter implements ActionFilter { private final Client client; private final BackendRegistry backendRegistry; + private final ClusterInfoHolder clusterInfoHolder; + public SecurityFilter(final Client client, final Settings settings, final PrivilegesEvaluator evalp, final AdminDNs adminDns, DlsFlsRequestValve dlsFlsValve, AuditLog auditLog, ThreadPool threadPool, ClusterService cs, - final CompatConfig compatConfig, final IndexResolverReplacer indexResolverReplacer, BackendRegistry backendRegistry) { + final CompatConfig compatConfig, final IndexResolverReplacer indexResolverReplacer, BackendRegistry backendRegistry, ClusterInfoHolder cih) { this.client = client; this.evalp = evalp; this.adminDns = adminDns; @@ -133,6 +140,7 @@ public SecurityFilter(final Client client, final Settings settings, final Privil this.immutableIndicesMatcher = WildcardMatcher.from(settings.getAsList(ConfigConstants.SECURITY_COMPLIANCE_IMMUTABLE_INDICES, Collections.emptyList())); this.rolesInjector = new RolesInjector(auditLog); this.backendRegistry = backendRegistry; + this.clusterInfoHolder = cih; log.info("{} indices are made immutable.", immutableIndicesMatcher); } @@ -386,15 +394,18 @@ private static boolean isUserAdmin(User user, final AdminDNs adminDns) { } private void attachSourceFieldContext(ActionRequest request) { + + Boolean hasOdfeNodes = clusterInfoHolder.getHasOdfeNodes(); + PackageBehavior packageBehavior = (hasOdfeNodes == null || hasOdfeNodes) ? PackageBehavior.REWRITE_AS_ODFE : PackageBehavior.NONE; if(request instanceof SearchRequest && SourceFieldsContext.isNeeded((SearchRequest) request)) { if(threadContext.getHeader("_opendistro_security_source_field_context") == null) { - final String serializedSourceFieldContext = Base64Helper.serializeObject(new SourceFieldsContext((SearchRequest) request)); + final String serializedSourceFieldContext = Base64Helper.serializeObject(new SourceFieldsContext((SearchRequest) request), packageBehavior); threadContext.putHeader("_opendistro_security_source_field_context", serializedSourceFieldContext); } } else if (request instanceof GetRequest && SourceFieldsContext.isNeeded((GetRequest) request)) { if(threadContext.getHeader("_opendistro_security_source_field_context") == null) { - final String serializedSourceFieldContext = Base64Helper.serializeObject(new SourceFieldsContext((GetRequest) request)); + final String serializedSourceFieldContext = Base64Helper.serializeObject(new SourceFieldsContext((GetRequest) request), packageBehavior); threadContext.putHeader("_opendistro_security_source_field_context", serializedSourceFieldContext); } } diff --git a/src/main/java/org/opensearch/security/privileges/DlsFlsEvaluator.java b/src/main/java/org/opensearch/security/privileges/DlsFlsEvaluator.java index 0b58b44375..ca8c004ee4 100644 --- a/src/main/java/org/opensearch/security/privileges/DlsFlsEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/DlsFlsEvaluator.java @@ -44,11 +44,13 @@ import org.opensearch.common.collect.Tuple; import org.opensearch.common.settings.Settings; import org.opensearch.common.util.concurrent.ThreadContext; +import org.opensearch.security.configuration.ClusterInfoHolder; import org.opensearch.security.securityconf.SecurityRoles; import org.opensearch.threadpool.ThreadPool; import org.opensearch.security.resolver.IndexResolverReplacer.Resolved; import org.opensearch.security.support.Base64Helper; +import org.opensearch.security.support.Base64Helper.PackageBehavior; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.support.WildcardMatcher; import org.opensearch.security.support.HeaderHelper; @@ -67,10 +69,13 @@ public DlsFlsEvaluator(Settings settings, ThreadPool threadPool) { } public PrivilegesEvaluatorResponse evaluate(final ActionRequest request, final ClusterService clusterService, final IndexNameExpressionResolver resolver, final Resolved requestedResolved, final User user, - final SecurityRoles securityRoles, final PrivilegesEvaluatorResponse presponse) { + final SecurityRoles securityRoles, final PrivilegesEvaluatorResponse presponse, final ClusterInfoHolder clusterInfoHolder) { ThreadContext threadContext = threadPool.getThreadContext(); + Boolean hasOdfeNodes = clusterInfoHolder.getHasOdfeNodes(); + PackageBehavior packageBehavior = (hasOdfeNodes == null || hasOdfeNodes) ? PackageBehavior.REWRITE_AS_ODFE : PackageBehavior.NONE; + // maskedFields final Map> maskedFieldsMap = securityRoles.getMaskedFields(user, resolver, clusterService); final boolean isDebugEnabled = log.isDebugEnabled(); @@ -78,7 +83,7 @@ public PrivilegesEvaluatorResponse evaluate(final ActionRequest request, final C if (maskedFieldsMap != null && !maskedFieldsMap.isEmpty()) { if(request instanceof ClusterSearchShardsRequest && HeaderHelper.isTrustedClusterRequest(threadContext)) { - threadContext.addResponseHeader(ConfigConstants.OPENDISTRO_SECURITY_MASKED_FIELD_HEADER, Base64Helper.serializeObject((Serializable) maskedFieldsMap)); + threadContext.addResponseHeader(ConfigConstants.OPENDISTRO_SECURITY_MASKED_FIELD_HEADER, Base64Helper.serializeObject((Serializable) maskedFieldsMap, packageBehavior)); if (isDebugEnabled) { log.debug("Added response header for masked fields info: {}", maskedFieldsMap); } @@ -92,7 +97,7 @@ public PrivilegesEvaluatorResponse evaluate(final ActionRequest request, final C } } } else { - threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_MASKED_FIELD_HEADER, Base64Helper.serializeObject((Serializable) maskedFieldsMap)); + threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_MASKED_FIELD_HEADER, Base64Helper.serializeObject((Serializable) maskedFieldsMap, packageBehavior)); if (isDebugEnabled) { log.debug("Attach masked fields info: {}", maskedFieldsMap); } @@ -116,7 +121,7 @@ public PrivilegesEvaluatorResponse evaluate(final ActionRequest request, final C if (!dlsQueries.isEmpty()) { if(request instanceof ClusterSearchShardsRequest && HeaderHelper.isTrustedClusterRequest(threadContext)) { - threadContext.addResponseHeader(ConfigConstants.OPENDISTRO_SECURITY_DLS_QUERY_HEADER, Base64Helper.serializeObject((Serializable) dlsQueries)); + threadContext.addResponseHeader(ConfigConstants.OPENDISTRO_SECURITY_DLS_QUERY_HEADER, Base64Helper.serializeObject((Serializable) dlsQueries, packageBehavior)); if (isDebugEnabled) { log.debug("Added response header for DLS info: {}", dlsQueries); } @@ -126,7 +131,7 @@ public PrivilegesEvaluatorResponse evaluate(final ActionRequest request, final C throw new OpenSearchSecurityException(ConfigConstants.OPENDISTRO_SECURITY_DLS_QUERY_HEADER + " does not match (SG 900D)"); } } else { - threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_DLS_QUERY_HEADER, Base64Helper.serializeObject((Serializable) dlsQueries)); + threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_DLS_QUERY_HEADER, Base64Helper.serializeObject((Serializable) dlsQueries, packageBehavior)); if (isDebugEnabled) { log.debug("Attach DLS info: {}", dlsQueries); } @@ -143,7 +148,7 @@ public PrivilegesEvaluatorResponse evaluate(final ActionRequest request, final C if (!flsFields.isEmpty()) { if(request instanceof ClusterSearchShardsRequest && HeaderHelper.isTrustedClusterRequest(threadContext)) { - threadContext.addResponseHeader(ConfigConstants.OPENDISTRO_SECURITY_FLS_FIELDS_HEADER, Base64Helper.serializeObject((Serializable) flsFields)); + threadContext.addResponseHeader(ConfigConstants.OPENDISTRO_SECURITY_FLS_FIELDS_HEADER, Base64Helper.serializeObject((Serializable) flsFields, packageBehavior)); if (isDebugEnabled) { log.debug("Added response header for FLS info: {}", flsFields); } @@ -157,7 +162,7 @@ public PrivilegesEvaluatorResponse evaluate(final ActionRequest request, final C } } } else { - threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_FLS_FIELDS_HEADER, Base64Helper.serializeObject((Serializable) flsFields)); + threadContext.putHeader(ConfigConstants.OPENDISTRO_SECURITY_FLS_FIELDS_HEADER, Base64Helper.serializeObject((Serializable) flsFields, packageBehavior)); if (isDebugEnabled) { log.debug("Attach FLS info: {}", flsFields); } diff --git a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java index 6a8aebcc38..240e7bf9f2 100644 --- a/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java +++ b/src/main/java/org/opensearch/security/privileges/PrivilegesEvaluator.java @@ -270,7 +270,7 @@ public PrivilegesEvaluatorResponse evaluate(final User user, String action0, fin // check dlsfls if (dlsFlsEnabled //&& (action0.startsWith("indices:data/read") || action0.equals(ClusterSearchShardsAction.NAME)) - && dlsFlsEvaluator.evaluate(request, clusterService, resolver, requestedResolved, user, securityRoles, presponse).isComplete()) { + && dlsFlsEvaluator.evaluate(request, clusterService, resolver, requestedResolved, user, securityRoles, presponse, clusterInfoHolder).isComplete()) { return presponse; } diff --git a/src/main/java/org/opensearch/security/rest/SecurityInfoAction.java b/src/main/java/org/opensearch/security/rest/SecurityInfoAction.java index 04a6b427fc..95ec62cde3 100644 --- a/src/main/java/org/opensearch/security/rest/SecurityInfoAction.java +++ b/src/main/java/org/opensearch/security/rest/SecurityInfoAction.java @@ -54,8 +54,10 @@ import org.opensearch.rest.RestController; import org.opensearch.rest.RestRequest; import org.opensearch.rest.RestStatus; +import org.opensearch.security.configuration.ClusterInfoHolder; import org.opensearch.security.privileges.PrivilegesEvaluator; import org.opensearch.security.support.Base64Helper; +import org.opensearch.security.support.Base64Helper.PackageBehavior; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.User; import org.opensearch.threadpool.ThreadPool; @@ -73,10 +75,13 @@ public class SecurityInfoAction extends BaseRestHandler { private final PrivilegesEvaluator evaluator; private final ThreadContext threadContext; - public SecurityInfoAction(final Settings settings, final RestController controller, final PrivilegesEvaluator evaluator, final ThreadPool threadPool) { + private final ClusterInfoHolder clusterInfoHolder; + + public SecurityInfoAction(final Settings settings, final RestController controller, final PrivilegesEvaluator evaluator, final ThreadPool threadPool, final ClusterInfoHolder clusterInfoHolder) { super(); this.threadContext = threadPool.getThreadContext(); this.evaluator = evaluator; + this.clusterInfoHolder = clusterInfoHolder; } @Override @@ -92,6 +97,9 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli public void accept(RestChannel channel) throws Exception { XContentBuilder builder = channel.newBuilder(); //NOSONAR BytesRestResponse response = null; + + Boolean hasOdfeNodes = clusterInfoHolder.getHasOdfeNodes(); + PackageBehavior packageBehavior = (hasOdfeNodes == null || hasOdfeNodes) ? PackageBehavior.REWRITE_AS_ODFE : PackageBehavior.NONE; try { @@ -119,9 +127,9 @@ public void accept(RestChannel channel) throws Exception { if(user != null && verbose) { try { - builder.field("size_of_user", RamUsageEstimator.humanReadableUnits(Base64Helper.serializeObject(user).length())); - builder.field("size_of_custom_attributes", RamUsageEstimator.humanReadableUnits(Base64Helper.serializeObject((Serializable) user.getCustomAttributesMap()).getBytes(StandardCharsets.UTF_8).length)); - builder.field("size_of_backendroles", RamUsageEstimator.humanReadableUnits(Base64Helper.serializeObject((Serializable)user.getRoles()).getBytes(StandardCharsets.UTF_8).length)); + builder.field("size_of_user", RamUsageEstimator.humanReadableUnits(Base64Helper.serializeObject(user, packageBehavior).length())); + builder.field("size_of_custom_attributes", RamUsageEstimator.humanReadableUnits(Base64Helper.serializeObject((Serializable) user.getCustomAttributesMap(), packageBehavior).getBytes(StandardCharsets.UTF_8).length)); + builder.field("size_of_backendroles", RamUsageEstimator.humanReadableUnits(Base64Helper.serializeObject((Serializable)user.getRoles(), packageBehavior).getBytes(StandardCharsets.UTF_8).length)); } catch (Throwable e) { //ignore } diff --git a/src/main/java/org/opensearch/security/support/Base64Helper.java b/src/main/java/org/opensearch/security/support/Base64Helper.java index e0722060e8..8645840644 100644 --- a/src/main/java/org/opensearch/security/support/Base64Helper.java +++ b/src/main/java/org/opensearch/security/support/Base64Helper.java @@ -59,6 +59,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -66,6 +67,7 @@ import org.opensearch.OpenSearchException; import org.opensearch.SpecialPermission; +import org.opensearch.Version; import org.opensearch.common.Strings; import org.opensearch.security.user.User; @@ -171,12 +173,18 @@ public ObjectStreamClass replace(final ObjectStreamClass desc) { } } + public enum PackageBehavior { + REWRITE_AS_ODFE, NONE + } + private final static class SafeObjectOutputStream extends ObjectOutputStream { private static final boolean useSafeObjectOutputStream = checkSubstitutionPermission(); private final DescriptorReplacer descriptorReplacer = new DescriptorReplacer(); + private boolean replaceWithOdfePackage = true; + private static boolean checkSubstitutionPermission() { SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -194,9 +202,9 @@ private static boolean checkSubstitutionPermission() { return true; } - static ObjectOutputStream create(ByteArrayOutputStream out) throws IOException { + static ObjectOutputStream create(ByteArrayOutputStream out, boolean replaceWithOdfePackage) throws IOException { try { - return useSafeObjectOutputStream ? new SafeObjectOutputStream(out) : new ObjectOutputStream(out); + return useSafeObjectOutputStream ? new SafeObjectOutputStream(out, replaceWithOdfePackage) : 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 @@ -205,8 +213,9 @@ static ObjectOutputStream create(ByteArrayOutputStream out) throws IOException { } } - private SafeObjectOutputStream(OutputStream out) throws IOException { + private SafeObjectOutputStream(OutputStream out, boolean replaceWithOdfePackage) throws IOException { super(out); + this.replaceWithOdfePackage = replaceWithOdfePackage; SecurityManager sm = System.getSecurityManager(); if (sm != null) { @@ -220,7 +229,11 @@ private SafeObjectOutputStream(OutputStream out) throws IOException { @Override protected void writeClassDescriptor(final ObjectStreamClass desc) throws IOException { - super.writeClassDescriptor(descriptorReplacer.replace(desc)); + if (replaceWithOdfePackage) { + super.writeClassDescriptor(descriptorReplacer.replace(desc)); + } else { + super.writeClassDescriptor(desc); + } } @Override @@ -233,12 +246,14 @@ protected Object replaceObject(Object obj) throws IOException { } } - public static String serializeObject(final Serializable object) { + public static String serializeObject(final Serializable object, PackageBehavior packageBehavior) { Preconditions.checkArgument(object != null, "object must not be null"); + boolean replaceWithOdfePackage = packageBehavior == PackageBehavior.REWRITE_AS_ODFE; + final ByteArrayOutputStream bos = new ByteArrayOutputStream(); - try (final ObjectOutputStream out = SafeObjectOutputStream.create(bos)) { + try (final ObjectOutputStream out = SafeObjectOutputStream.create(bos, replaceWithOdfePackage)) { out.writeObject(object); } catch (final Exception e) { throw new OpenSearchException("Instance {} of class {} is not serializable", e, object, object.getClass()); diff --git a/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java b/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java index acca8f8f28..adca56264e 100644 --- a/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java +++ b/src/main/java/org/opensearch/security/transport/SecurityInterceptor.java @@ -68,13 +68,11 @@ import org.opensearch.security.auth.BackendRegistry; import org.opensearch.security.ssl.SslExceptionHandler; import org.opensearch.security.support.Base64Helper; +import org.opensearch.security.support.Base64Helper.PackageBehavior; import org.opensearch.security.support.ConfigConstants; import org.opensearch.security.user.User; -import org.opensearch.security.OpenSearchSecurityPlugin; -import org.opensearch.security.configuration.ClusterInfoHolder; import org.opensearch.security.ssl.transport.SSLConfig; -import org.opensearch.security.ssl.transport.PrincipalExtractor; import com.google.common.collect.Maps; @@ -212,6 +210,9 @@ private void ensureCorrectHeaders(final Object remoteAdr, final User origUser, f final String injectedUserString, final String injectedRolesString) { // keep original address + Boolean hasOdfeNodes = clusterInfoHolder.getHasOdfeNodes(); + PackageBehavior packageBehavior = (hasOdfeNodes == null || hasOdfeNodes) ? PackageBehavior.REWRITE_AS_ODFE : PackageBehavior.NONE; + if(origin != null && !origin.isEmpty() /*&& !Origin.LOCAL.toString().equalsIgnoreCase(origin)*/ && getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN_HEADER) == null) { getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_ORIGIN_HEADER, origin); } @@ -225,7 +226,7 @@ private void ensureCorrectHeaders(final Object remoteAdr, final User origUser, f String remoteAddressHeader = getThreadContext().getHeader(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS_HEADER); if(remoteAddressHeader == null) { - getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS_HEADER, Base64Helper.serializeObject(((TransportAddress) remoteAdr).address())); + getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_REMOTE_ADDRESS_HEADER, Base64Helper.serializeObject(((TransportAddress) remoteAdr).address(), packageBehavior)); } } @@ -234,7 +235,7 @@ private void ensureCorrectHeaders(final Object remoteAdr, final User origUser, f if(userHeader == null) { if(origUser != null) { - getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, Base64Helper.serializeObject(origUser)); + getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_USER_HEADER, Base64Helper.serializeObject(origUser, packageBehavior)); } else if(StringUtils.isNotEmpty(injectedRolesString)) { getThreadContext().putHeader(ConfigConstants.OPENDISTRO_SECURITY_INJECTED_ROLES_HEADER, injectedRolesString); diff --git a/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java b/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java index 5bcf0cbbcf..e150f33d65 100644 --- a/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java +++ b/src/test/java/com/amazon/dlic/auth/http/jwt/HTTPJwtAuthenticatorTest.java @@ -472,7 +472,7 @@ public void testRS256() throws Exception { public void testES512() throws Exception { KeyPairGenerator keyGen = KeyPairGenerator.getInstance("EC"); - keyGen.initialize(571); + keyGen.initialize(521); KeyPair pair = keyGen.generateKeyPair(); PrivateKey priv = pair.getPrivate(); PublicKey pub = pair.getPublic(); diff --git a/src/test/java/org/opensearch/security/filter/SecurityFilterTest.java b/src/test/java/org/opensearch/security/filter/SecurityFilterTest.java index c28281fc26..0be6e525ee 100644 --- a/src/test/java/org/opensearch/security/filter/SecurityFilterTest.java +++ b/src/test/java/org/opensearch/security/filter/SecurityFilterTest.java @@ -19,6 +19,7 @@ import org.opensearch.security.auditlog.AuditLog; import org.opensearch.security.auth.BackendRegistry; import org.opensearch.security.configuration.AdminDNs; +import org.opensearch.security.configuration.ClusterInfoHolder; import org.opensearch.security.configuration.CompatConfig; import org.opensearch.security.configuration.DlsFlsRequestValve; import org.opensearch.security.privileges.PrivilegesEvaluator; @@ -88,7 +89,8 @@ public void testImmutableIndicesWildcardMatcher() { mock(ClusterService.class), mock(CompatConfig.class), mock(IndexResolverReplacer.class), - mock(BackendRegistry.class) + mock(BackendRegistry.class), + mock(ClusterInfoHolder.class) ); assertEquals(expected, filter.getImmutableIndicesMatcher()); } @@ -112,7 +114,8 @@ public void testUnexepectedCausesAreNotSendToCallers() { mock(ClusterService.class), mock(CompatConfig.class), mock(IndexResolverReplacer.class), - mock(BackendRegistry.class) + mock(BackendRegistry.class), + mock(ClusterInfoHolder.class) ); // Act diff --git a/src/test/java/org/opensearch/security/support/Base64HelperTest.java b/src/test/java/org/opensearch/security/support/Base64HelperTest.java index d2921b286c..01e0e0bd0b 100644 --- a/src/test/java/org/opensearch/security/support/Base64HelperTest.java +++ b/src/test/java/org/opensearch/security/support/Base64HelperTest.java @@ -32,6 +32,7 @@ import com.google.common.io.BaseEncoding; +import org.opensearch.security.support.Base64Helper.PackageBehavior; import static org.opensearch.security.support.Base64Helper.deserializeObject; import static org.opensearch.security.support.Base64Helper.serializeObject; @@ -41,67 +42,126 @@ private static final class NotSafeSerializable implements Serializable { private static final long serialVersionUID = 5135559266828470092L; } - private static Serializable ds(Serializable s) { - return deserializeObject(serializeObject(s)); + private static Serializable ds(Serializable s, PackageBehavior packageBehavior) { + return deserializeObject(serializeObject(s, packageBehavior)); } @Test public void testString() { String string = "string"; - Assert.assertEquals(string, ds(string)); + Assert.assertEquals(string, ds(string, PackageBehavior.NONE)); } @Test public void testInteger() { Integer integer = Integer.valueOf(0); - Assert.assertEquals(integer, ds(integer)); + Assert.assertEquals(integer, ds(integer, PackageBehavior.NONE)); } @Test public void testDouble() { Double number = Double.valueOf(0.); - Assert.assertEquals(number, ds(number)); + Assert.assertEquals(number, ds(number, PackageBehavior.NONE)); } @Test public void testInetSocketAddress() { InetSocketAddress inetSocketAddress = new InetSocketAddress(0); - Assert.assertEquals(inetSocketAddress, ds(inetSocketAddress)); + Assert.assertEquals(inetSocketAddress, ds(inetSocketAddress, PackageBehavior.NONE)); } @Test public void testPattern() { Pattern pattern = Pattern.compile(".*"); - Assert.assertEquals(pattern.pattern(), ((Pattern) ds(pattern)).pattern()); + Assert.assertEquals(pattern.pattern(), ((Pattern) ds(pattern, PackageBehavior.NONE)).pattern()); } @Test public void testUser() { User user = new User("user"); - Assert.assertEquals(user, ds(user)); + Assert.assertEquals(user, ds(user, PackageBehavior.NONE)); } @Test public void testSourceFieldsContext() { SourceFieldsContext sourceFieldsContext = new SourceFieldsContext(new SearchRequest("")); - Assert.assertEquals(sourceFieldsContext.toString(), ds(sourceFieldsContext).toString()); + Assert.assertEquals(sourceFieldsContext.toString(), ds(sourceFieldsContext, PackageBehavior.NONE).toString()); } @Test public void testHashMap() { HashMap map = new HashMap(); - Assert.assertEquals(map, ds(map)); + Assert.assertEquals(map, ds(map, PackageBehavior.NONE)); } @Test public void testArrayList() { ArrayList list = new ArrayList(); - Assert.assertEquals(list, ds(list)); + Assert.assertEquals(list, ds(list, PackageBehavior.NONE)); } @Test(expected = OpenSearchException.class) public void notSafeSerializable() { - serializeObject(new NotSafeSerializable()); + serializeObject(new NotSafeSerializable(), PackageBehavior.NONE); + } + + @Test + public void testStringWithRewriteOdfePackage() { + String string = "string"; + Assert.assertEquals(string, ds(string, PackageBehavior.REWRITE_AS_ODFE)); + } + + @Test + public void testIntegerWithRewriteOdfePackage() { + Integer integer = Integer.valueOf(0); + Assert.assertEquals(integer, ds(integer, PackageBehavior.REWRITE_AS_ODFE)); + } + + @Test + public void testDoubleWithRewriteOdfePackage() { + Double number = Double.valueOf(0.); + Assert.assertEquals(number, ds(number, PackageBehavior.REWRITE_AS_ODFE)); + } + + @Test + public void testInetSocketAddressWithRewriteOdfePackage() { + InetSocketAddress inetSocketAddress = new InetSocketAddress(0); + Assert.assertEquals(inetSocketAddress, ds(inetSocketAddress, PackageBehavior.REWRITE_AS_ODFE)); + } + + @Test + public void testPatternWithRewriteOdfePackage() { + Pattern pattern = Pattern.compile(".*"); + Assert.assertEquals(pattern.pattern(), ((Pattern) ds(pattern, PackageBehavior.REWRITE_AS_ODFE)).pattern()); + } + + @Test + public void testUserWithRewriteOdfePackage() { + User user = new User("user"); + Assert.assertEquals(user, ds(user, PackageBehavior.REWRITE_AS_ODFE)); + } + + @Test + public void testSourceFieldsContextWithRewriteOdfePackage() { + SourceFieldsContext sourceFieldsContext = new SourceFieldsContext(new SearchRequest("")); + Assert.assertEquals(sourceFieldsContext.toString(), ds(sourceFieldsContext, PackageBehavior.REWRITE_AS_ODFE).toString()); + } + + @Test + public void testHashMapWithRewriteOdfePackage() { + HashMap map = new HashMap(); + Assert.assertEquals(map, ds(map, PackageBehavior.REWRITE_AS_ODFE)); + } + + @Test + public void testArrayListWithRewriteOdfePackage() { + ArrayList list = new ArrayList(); + Assert.assertEquals(list, ds(list, PackageBehavior.REWRITE_AS_ODFE)); + } + + @Test(expected = OpenSearchException.class) + public void notSafeSerializableWithRewriteOdfePackage() { + serializeObject(new NotSafeSerializable(), PackageBehavior.REWRITE_AS_ODFE); } @Test(expected = OpenSearchException.class)