Skip to content

Commit

Permalink
GEODE-9714: Add Shiro packages to sanctioned serializables (apache#7001)
Browse files Browse the repository at this point in the history
Adds all Shiro subpackages that contain exceptions to the list of
sanctioned serializables.

PROBLEM

QueryConfigurationServiceConstraintsDistributedTest failed in
CI when it tried to deserialize
org.apache.shiro.session.StoppedSessionException.

SOLUTION

I did some research and I believe we should add all Shiro
subpackages containing exceptions to the accept-list.
  • Loading branch information
kirklund authored Oct 19, 2021
1 parent 726d537 commit a2a80ed
Show file tree
Hide file tree
Showing 3 changed files with 178 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
*/
@MakeNotStatic
private static final Map<String, DataSerializer> classesToSerializers = new ConcurrentHashMap<>();

/**
* This list contains classes that Geode's classes subclass, such as antlr AST classes which are
* used by our Object Query Language. It also contains certain classes that are DataSerializable
Expand All @@ -179,6 +180,11 @@ public abstract class InternalDataSerializer extends DataSerializer {
* Do not add to this list unless absolutely necessary. Instead, put your classes either in the
* sanctionedSerializables file for your module or in its excludedClasses file. Run
* AnalyzeSerializables to generate the content for the file.
*
* <p>
* Syntax is documented by the javadocs of {@code ObjectInputFilter.Config.createFilter}. In
* Java 8, {@code ObjectInputFilter} is in package {@code sun.misc}. In Java 9 and above, it's
* in package {@code java.io}.
*/
private static final String SANCTIONED_SERIALIZABLES_DEPENDENCIES_PATTERN =
// Java
Expand Down Expand Up @@ -210,9 +216,7 @@ public abstract class InternalDataSerializer extends DataSerializer {
+ ";org.apache.geode.internal.cache.tier.sockets.VersionedObjectList"

// security services
+ ";org.apache.shiro.*"
+ ";org.apache.shiro.authz.*"
+ ";org.apache.shiro.authc.*"
+ ";org.apache.shiro.**"

// export logs
+ ";org.apache.logging.log4j.Level"
Expand All @@ -223,12 +227,14 @@ public abstract class InternalDataSerializer extends DataSerializer {
+ ";com.healthmarketscience.rmiio.RemoteInputStream"
+ ";javax.rmi.ssl.SslRMIClientSocketFactory"
+ ";javax.net.ssl.SSLHandshakeException"
+ ";javax.net.ssl.SSLException;sun.security.validator.ValidatorException"
+ ";javax.net.ssl.SSLException"
+ ";sun.security.validator.ValidatorException"
+ ";sun.security.provider.certpath.SunCertPathBuilderException"

// geode-modules
+ ";org.apache.geode.modules.util.SessionCustomExpiry"
+ ";";

private static final String serializationVersionTxt =
System.getProperty(GeodeGlossary.GEMFIRE_PREFIX + "serializationVersion");
/**
Expand Down Expand Up @@ -436,7 +442,8 @@ public static void initializeSerializationFilter(DistributionConfig distribution
}
}

private static void clearSerializationFilter() {
@VisibleForTesting
static void clearSerializationFilter() {
serializationFilter = defaultSerializationFilter;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import java.io.Serializable;
import java.util.Properties;

import org.junit.AfterClass;
import org.junit.After;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
Expand All @@ -50,7 +50,7 @@ public class InternalDataSerializerSerializationAcceptlistTest {

@BeforeClass
public static void hasObjectInputFilter() {
assumeTrue("ObjectInputFilter is present in this JVM (post- 8.111)",
assumeTrue("ObjectInputFilter is present in this JVM",
isClassAvailable("sun.misc.ObjectInputFilter") ||
isClassAvailable("java.io.ObjectInputFilter"));
}
Expand All @@ -62,10 +62,9 @@ public void setUp() {
properties = new Properties();
}

@AfterClass
public static void clearDataSerializerFilter() {
InternalDataSerializer
.initializeSerializationFilter(new DistributionConfigImpl(new Properties()), emptySet());
@After
public void clearSerializationFilter() {
InternalDataSerializer.clearSerializationFilter();
}

@Test
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more contributor license
* agreements. See the NOTICE file distributed with this work for additional information regarding
* copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance with the License. You may obtain a
* copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under the License
* is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions and limitations under
* the License.
*/
package org.apache.geode.internal;

import static java.util.Collections.emptySet;
import static org.apache.geode.distributed.internal.DistributionConfig.VALIDATE_SERIALIZABLE_OBJECTS_NAME;
import static org.apache.geode.internal.lang.ClassUtils.isClassAvailable;
import static org.apache.geode.internal.serialization.KnownVersion.CURRENT;
import static org.junit.Assume.assumeTrue;

import java.io.ByteArrayInputStream;
import java.io.DataInputStream;
import java.io.IOException;
import java.util.Properties;

import org.apache.shiro.ShiroException;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authz.AuthorizationException;
import org.apache.shiro.codec.CodecException;
import org.apache.shiro.config.ConfigurationException;
import org.apache.shiro.crypto.UnknownAlgorithmException;
import org.apache.shiro.dao.InvalidResourceUsageException;
import org.apache.shiro.env.RequiredTypeException;
import org.apache.shiro.io.SerializationException;
import org.apache.shiro.ldap.UnsupportedAuthenticationMechanismException;
import org.apache.shiro.session.SessionException;
import org.apache.shiro.session.StoppedSessionException;
import org.apache.shiro.subject.ExecutionException;
import org.junit.After;
import org.junit.BeforeClass;
import org.junit.Test;
import org.junit.experimental.categories.Category;

import org.apache.geode.DataSerializer;
import org.apache.geode.distributed.internal.DistributionConfig;
import org.apache.geode.distributed.internal.DistributionConfigImpl;
import org.apache.geode.test.junit.categories.SecurityTest;
import org.apache.geode.test.junit.categories.SerializationTest;

@Category({SecurityTest.class, SerializationTest.class})
public class InternalDataSerializerShiroAcceptListTest {

@BeforeClass
public static void hasObjectInputFilter() {
assumeTrue("ObjectInputFilter is present in this JVM",
isClassAvailable("sun.misc.ObjectInputFilter") ||
isClassAvailable("java.io.ObjectInputFilter"));
}

@After
public void clearSerializationFilter() {
InternalDataSerializer.clearSerializationFilter();
}

@Test
public void acceptsAuthenticationException() throws IOException, ClassNotFoundException {
trySerializingObject(new AuthenticationException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsAuthorizationException() throws IOException, ClassNotFoundException {
trySerializingObject(new AuthorizationException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsCodecException() throws IOException, ClassNotFoundException {
trySerializingObject(new CodecException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsConfigurationException() throws IOException, ClassNotFoundException {
trySerializingObject(new ConfigurationException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsExecutionException() throws IOException, ClassNotFoundException {
trySerializingObject(new ExecutionException("testing", new Exception("testing")),
propertiesWithoutFilter());
}

@Test
public void acceptsInstantiationException() throws IOException, ClassNotFoundException {
trySerializingObject(new org.apache.shiro.util.InstantiationException("testing"),
propertiesWithoutFilter());
}

@Test
public void acceptsInvalidResourceUsageException() throws IOException, ClassNotFoundException {
trySerializingObject(new InvalidResourceUsageException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsRequiredTypeException() throws IOException, ClassNotFoundException {
trySerializingObject(new RequiredTypeException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsSerializationException() throws IOException, ClassNotFoundException {
trySerializingObject(new SerializationException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsSessionException() throws IOException, ClassNotFoundException {
trySerializingObject(new SessionException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsShiroException() throws IOException, ClassNotFoundException {
trySerializingObject(new ShiroException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsStoppedSessionException() throws IOException, ClassNotFoundException {
trySerializingObject(new StoppedSessionException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsUnknownAlgorithmException() throws IOException, ClassNotFoundException {
trySerializingObject(new UnknownAlgorithmException("testing"), propertiesWithoutFilter());
}

@Test
public void acceptsUnsupportedAuthenticationMechanismException()
throws IOException, ClassNotFoundException {
trySerializingObject(new UnsupportedAuthenticationMechanismException("testing"),
propertiesWithoutFilter());
}

private static Properties propertiesWithoutFilter() {
Properties properties = new Properties();
properties.setProperty(VALIDATE_SERIALIZABLE_OBJECTS_NAME, "true");

return properties;
}

private static void trySerializingObject(Object object, Properties properties)
throws IOException, ClassNotFoundException {
DistributionConfig distributionConfig = new DistributionConfigImpl(properties);
InternalDataSerializer.initializeSerializationFilter(distributionConfig, emptySet());
HeapDataOutputStream outputStream = new HeapDataOutputStream(CURRENT);

DataSerializer.writeObject(object, outputStream);

try (ByteArrayInputStream bais = new ByteArrayInputStream(outputStream.toByteArray());
DataInputStream dis = new DataInputStream(bais)) {
DataSerializer.readObject(dis);
}
}
}

0 comments on commit a2a80ed

Please sign in to comment.