下面列出了怎么用java.io.ObjectInputFilter的API类实例代码及写法,或者点击链接到github查看源代码。
/**
* Creates a new <code>MarshalledObjectInputStream</code> that
* reads its objects from <code>objIn</code> and annotations
* from <code>locIn</code>. If <code>locIn</code> is
* <code>null</code>, then all annotations will be
* <code>null</code>.
*/
MarshalledObjectInputStream(InputStream objIn, InputStream locIn,
ObjectInputFilter filter)
throws IOException
{
super(objIn);
this.locIn = (locIn == null ? null : new ObjectInputStream(locIn));
if (filter != null) {
AccessController.doPrivileged((PrivilegedAction<Void>) () -> {
MarshalledObjectInputStream.this.setObjectInputFilter(filter);
if (MarshalledObjectInputStream.this.locIn != null) {
MarshalledObjectInputStream.this.locIn.setObjectInputFilter(filter);
}
return null;
});
}
}
/**
* Initialize the registryFilter from the security properties or system property; if any
* @return an ObjectInputFilter, or null
*/
@SuppressWarnings("deprecation")
private static ObjectInputFilter initRegistryFilter() {
ObjectInputFilter filter = null;
String props = System.getProperty(REGISTRY_FILTER_PROPNAME);
if (props == null) {
props = Security.getProperty(REGISTRY_FILTER_PROPNAME);
}
if (props != null) {
filter = ObjectInputFilter.Config.createFilter(props);
Log regLog = Log.getLog("sun.rmi.registry", "registry", -1);
if (regLog.isLoggable(Log.BRIEF)) {
regLog.log(Log.BRIEF, "registryFilter = " + filter);
}
}
return filter;
}
/**
* Read objects from the serialized stream, validated with the filter.
*
* @param bytes a byte array to read objects from
* @param filter the ObjectInputFilter
* @return the object deserialized if any
* @throws IOException can be thrown
*/
static Object validate(byte[] bytes,
ObjectInputFilter filter) throws IOException {
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais)) {
ois.setObjectInputFilter(filter);
Object o = ois.readObject();
return o;
} catch (EOFException eof) {
// normal completion
} catch (ClassNotFoundException cnf) {
Assert.fail("Deserializing", cnf);
}
return null;
}
@Override
public ObjectInputFilter.Status checkInput(FilterInfo filter) {
Class<?> serialClass = filter.serialClass();
System.out.printf(" checkInput: class: %s, arrayLen: %d, refs: %d, depth: %d, bytes; %d%n",
serialClass, filter.arrayLength(), filter.references(),
filter.depth(), filter.streamBytes());
count++;
if (serialClass != null) {
if (serialClass.getName().contains("$$Lambda$")) {
// TBD: proper identification of serialized Lambdas?
// Fold the serialized Lambda into the SerializedLambda type
classes.add(SerializedLambda.class);
} else if (Proxy.isProxyClass(serialClass)) {
classes.add(Proxy.class);
} else {
classes.add(serialClass);
}
}
this.maxArray = Math.max(this.maxArray, filter.arrayLength());
this.maxRefs = Math.max(this.maxRefs, filter.references());
this.maxDepth = Math.max(this.maxDepth, filter.depth());
this.maxBytes = Math.max(this.maxBytes, filter.streamBytes());
return ObjectInputFilter.Status.UNDECIDED;
}
/**
* Test that setting process-wide filter is checked by security manager.
*/
@Test
public void testGlobalFilter() throws Exception {
ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter();
try {
ObjectInputFilter.Config.setSerialFilter(filter);
assertFalse(setSecurityManager,
"When SecurityManager exists, without "
+ "java.io.SerializablePermission(serialFilter) "
+ "IllegalStateException should be thrown");
} catch (AccessControlException ex) {
assertTrue(setSecurityManager);
assertTrue(ex.getMessage().contains("java.io.SerializablePermission"));
assertTrue(ex.getMessage().contains("serialFilter"));
} catch (IllegalStateException ise) {
// ISE should occur only if global filter already set
Assert.assertNotNull(global, "Global filter should be non-null");
}
}
@Override
public Status checkInput(FilterInfo filterInfo) {
Status status = null;
if (delegate != null) {
status = delegate.checkInput(filterInfo);
if (status != Status.UNDECIDED) {
return status;
}
}
ObjectInputFilter serialFilter = ObjectInputFilter.Config.getSerialFilter();
if (serialFilter != null) {
status = serialFilter.checkInput(filterInfo);
if (status != Status.UNDECIDED) {
// The process-wide filter overrides this filter
return status;
}
}
if (filterInfo.serialClass() != null) {
String name = filterInfo.serialClass().getName();
if (isAllowedByDefault(name) || isRequiredPackage(name)) {
return Status.ALLOWED;
}
}
return Status.REJECTED;
}
/**
* ObjectInputFilter to check parameters to SingleEntryRegistry.
* Since it is a read-only Registry, no classes are accepted.
* String arguments are accepted without passing them to the serialFilter.
*
* @param info a reference to the serialization filter information
* @return Status.REJECTED if parameters are out of range
*/
private static ObjectInputFilter.Status singleRegistryFilter(ObjectInputFilter.FilterInfo info) {
return (info.serialClass() != null ||
info.depth() > 2 ||
info.references() > 4 ||
info.arrayLength() >= 0)
? ObjectInputFilter.Status.REJECTED
: ObjectInputFilter.Status.ALLOWED;
}
/**
* ObjectInputFilter to filter DGCClient return value (a Lease).
* The list of acceptable classes is very short and explicit.
* The depth and array sizes are limited.
*
* @param filterInfo access to class, arrayLength, etc.
* @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
* {@link ObjectInputFilter.Status#REJECTED} if rejected,
* otherwise {@link ObjectInputFilter.Status#UNDECIDED}
*/
private static ObjectInputFilter.Status leaseFilter(ObjectInputFilter.FilterInfo filterInfo) {
if (filterInfo.depth() > DGCCLIENT_MAX_DEPTH) {
return ObjectInputFilter.Status.REJECTED;
}
Class<?> clazz = filterInfo.serialClass();
if (clazz != null) {
while (clazz.isArray()) {
if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > DGCCLIENT_MAX_ARRAY_SIZE) {
return ObjectInputFilter.Status.REJECTED;
}
// Arrays are allowed depending on the component type
clazz = clazz.getComponentType();
}
if (clazz.isPrimitive()) {
// Arrays of primitives are allowed
return ObjectInputFilter.Status.ALLOWED;
}
return (clazz == UID.class ||
clazz == VMID.class ||
clazz == Lease.class)
? ObjectInputFilter.Status.ALLOWED
: ObjectInputFilter.Status.REJECTED;
}
// Not a class, not size limited
return ObjectInputFilter.Status.UNDECIDED;
}
/**
* Initialize the dgcFilter from the security properties or system property; if any
* @return an ObjectInputFilter, or null
*/
private static ObjectInputFilter initDgcFilter() {
ObjectInputFilter filter = null;
String props = System.getProperty(DGC_FILTER_PROPNAME);
if (props == null) {
props = Security.getProperty(DGC_FILTER_PROPNAME);
}
if (props != null) {
filter = ObjectInputFilter.Config.createFilter(props);
if (dgcLog.isLoggable(Log.BRIEF)) {
dgcLog.log(Log.BRIEF, "dgcFilter = " + filter);
}
}
return filter;
}
/**
* ObjectInputFilter to filter DGC input objects.
* The list of acceptable classes is very short and explicit.
* The depth and array sizes are limited.
*
* @param filterInfo access to class, arrayLength, etc.
* @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
* {@link ObjectInputFilter.Status#REJECTED} if rejected,
* otherwise {@link ObjectInputFilter.Status#UNDECIDED}
*/
private static ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo filterInfo) {
if (dgcFilter != null) {
ObjectInputFilter.Status status = dgcFilter.checkInput(filterInfo);
if (status != ObjectInputFilter.Status.UNDECIDED) {
// The DGC filter can override the built-in white-list
return status;
}
}
if (filterInfo.depth() > DGC_MAX_DEPTH) {
return ObjectInputFilter.Status.REJECTED;
}
Class<?> clazz = filterInfo.serialClass();
if (clazz != null) {
while (clazz.isArray()) {
if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > DGC_MAX_ARRAY_SIZE) {
return ObjectInputFilter.Status.REJECTED;
}
// Arrays are allowed depending on the component type
clazz = clazz.getComponentType();
}
if (clazz.isPrimitive()) {
// Arrays of primitives are allowed
return ObjectInputFilter.Status.ALLOWED;
}
return (clazz == ObjID.class ||
clazz == UID.class ||
clazz == VMID.class ||
clazz == Lease.class)
? ObjectInputFilter.Status.ALLOWED
: ObjectInputFilter.Status.REJECTED;
}
// Not a class, not size limited
return ObjectInputFilter.Status.UNDECIDED;
}
/**
* Construct a Unicast server remote reference to be exported
* on the specified port.
*/
public UnicastServerRef2(int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf,
ObjectInputFilter filter)
{
super(new LiveRef(port, csf, ssf), filter);
}
/**
* Test that the filter on a OIS can be set only on a fresh OIS,
* before deserializing any objects.
* This test is agnostic the global filter being set or not.
*/
@Test
static void nonResettableFilter() {
Validator validator1 = new Validator();
Validator validator2 = new Validator();
try {
byte[] bytes = writeObjects("text1"); // an object
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais)) {
// Check the initial filter is the global filter; may be null
ObjectInputFilter global = ObjectInputFilter.Config.getSerialFilter();
ObjectInputFilter initial = ois.getObjectInputFilter();
Assert.assertEquals(global, initial, "initial filter should be the global filter");
// Check if it can be set to null
ois.setObjectInputFilter(null);
ObjectInputFilter filter = ois.getObjectInputFilter();
Assert.assertNull(filter, "set to null should be null");
ois.setObjectInputFilter(validator1);
Object o = ois.readObject();
try {
ois.setObjectInputFilter(validator2);
Assert.fail("Should not be able to set filter twice");
} catch (IllegalStateException ise) {
// success, the exception was expected
}
} catch (EOFException eof) {
Assert.fail("Should not reach end-of-file", eof);
} catch (ClassNotFoundException cnf) {
Assert.fail("Deserializing", cnf);
}
} catch (IOException ex) {
Assert.fail("Unexpected IOException", ex);
}
}
/**
* Test repeated limits use the last value.
* Construct a filter with the limit and the limit repeated -1.
* Invoke the filter with the limit to make sure it is rejected.
* Invoke the filter with the limit -1 to make sure it is accepted.
* @param name the name of the limit to test
* @param value a test value
*/
@Test(dataProvider="Limits")
static void testLimits(String name, long value) {
Class<?> arrayClass = new int[0].getClass();
String pattern = String.format("%s=%d;%s=%d", name, value, name, value - 1);
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
Assert.assertEquals(
filter.checkInput(new FilterValues(arrayClass, value, value, value, value)),
ObjectInputFilter.Status.REJECTED,
"last limit value not used: " + filter);
Assert.assertEquals(
filter.checkInput(new FilterValues(arrayClass, value-1, value-1, value-1, value-1)),
ObjectInputFilter.Status.UNDECIDED,
"last limit value not used: " + filter);
}
/**
* Test invalid limits.
* Construct a filter with the limit, it should throw IllegalArgumentException.
* @param pattern a pattern to test
*/
@Test(dataProvider="InvalidLimits", expectedExceptions=java.lang.IllegalArgumentException.class)
static void testInvalidLimits(String pattern) {
try {
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
} catch (IllegalArgumentException iae) {
System.out.printf(" success exception: %s%n", iae);
throw iae;
}
}
/**
* Test that returning null from a filter causes deserialization to fail.
*/
@Test(expectedExceptions=InvalidClassException.class)
static void testNullStatus() throws IOException {
byte[] bytes = writeObjects(0); // an Integer
try {
Object o = validate(bytes, new ObjectInputFilter() {
public ObjectInputFilter.Status checkInput(ObjectInputFilter.FilterInfo f) {
return null;
}
});
} catch (InvalidClassException ice) {
System.out.printf(" success exception: %s%n", ice);
throw ice;
}
}
/**
* Verify that malformed patterns throw IAE.
* @param pattern pattern from the data source
*/
@Test(dataProvider="InvalidPatterns", expectedExceptions=IllegalArgumentException.class)
static void testInvalidPatterns(String pattern) {
try {
ObjectInputFilter.Config.createFilter(pattern);
} catch (IllegalArgumentException iae) {
System.out.printf(" success exception: %s%n", iae);
throw iae;
}
}
/**
* Test that Config.create returns null if the argument does not contain any patterns or limits.
*/
@Test()
static void testEmptyPattern() {
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter("");
Assert.assertNull(filter, "empty pattern did not return null");
filter = ObjectInputFilter.Config.createFilter(";;;;");
Assert.assertNull(filter, "pattern with only delimiters did not return null");
}
/**
* Create a filter from a pattern and API factory, then serialize and
* deserialize an object and check allowed or reject.
*
* @param pattern the pattern
* @param object the test object
* @param allowed the expected result from ObjectInputStream (exception or not)
*/
static void testPatterns(String pattern, Object object, boolean allowed) {
try {
byte[] bytes = SerialFilterTest.writeObjects(object);
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
validate(bytes, filter);
Assert.assertTrue(allowed, "filter should have thrown an exception");
} catch (IllegalArgumentException iae) {
Assert.fail("bad format pattern", iae);
} catch (InvalidClassException ice) {
Assert.assertFalse(allowed, "filter should not have thrown an exception: " + ice);
} catch (IOException ioe) {
Assert.fail("Unexpected IOException", ioe);
}
}
@Override
public ObjectInputFilter.Status checkInput(FilterInfo filter) {
if (ReadResolveToArray.class.isAssignableFrom(filter.serialClass())) {
return ObjectInputFilter.Status.ALLOWED;
}
if (filter.serialClass() != array.getClass() ||
(filter.arrayLength() >= 0 && filter.arrayLength() != length)) {
return ObjectInputFilter.Status.REJECTED;
}
return ObjectInputFilter.Status.UNDECIDED;
}
/**
* Test that the process-wide filter is set when the properties are set
* and has the toString matching the configured pattern.
*/
@Test()
static void globalFilter() {
String pattern =
System.getProperty("jdk.serialFilter",
Security.getProperty("jdk.serialFilter"));
ObjectInputFilter filter = ObjectInputFilter.Config.getSerialFilter();
System.out.printf("global pattern: %s, filter: %s%n", pattern, filter);
Assert.assertEquals(pattern, Objects.toString(filter, null),
"process-wide filter pattern does not match");
}
/**
* Test:
* "global filter reject" + "specific ObjectInputStream filter is empty" => should reject
* "global filter reject" + "specific ObjectInputStream filter allow" => should allow
*/
@Test(dataProvider="Patterns")
public void testRejectedInGlobal(Object toDeserialized, String pattern, boolean allowed) throws Exception {
byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais)) {
ois.setObjectInputFilter(filter);
Object o = ois.readObject();
assertTrue(allowed, "filter should have thrown an exception");
} catch (InvalidClassException ice) {
assertFalse(allowed, "filter should have thrown an exception");
}
}
@BeforeClass
public void setup() throws Exception {
setSecurityManager = System.getSecurityManager() != null;
Object toDeserialized = Long.MAX_VALUE;
bytes = SerialFilterTest.writeObjects(toDeserialized);
filter = ObjectInputFilter.Config.createFilter("java.lang.Long");
}
public static JavaObjectInputFilterAccess getJavaObjectInputFilterAccess() {
if (javaObjectInputFilterAccess == null) {
unsafe.ensureClassInitialized(ObjectInputFilter.Config.class);
}
return javaObjectInputFilterAccess;
}
/**
* Construct a Unicast server remote reference for a specified
* liveRef and filter.
*/
public UnicastServerRef2(LiveRef ref,
ObjectInputFilter filter)
{
super(ref, filter);
}
/**
* Construct a Unicast server remote reference for a specified
* liveRef and filter.
*/
public UnicastServerRef(LiveRef ref, ObjectInputFilter filter) {
super(ref);
this.filter = filter;
}
/**
* ObjectInputFilter to filter Registry input objects.
* The list of acceptable classes is limited to classes normally
* stored in a registry.
*
* @param filterInfo access to the class, array length, etc.
* @return {@link ObjectInputFilter.Status#ALLOWED} if allowed,
* {@link ObjectInputFilter.Status#REJECTED} if rejected,
* otherwise {@link ObjectInputFilter.Status#UNDECIDED}
*/
private static ObjectInputFilter.Status registryFilter(ObjectInputFilter.FilterInfo filterInfo) {
if (registryFilter != null) {
ObjectInputFilter.Status status = registryFilter.checkInput(filterInfo);
if (status != ObjectInputFilter.Status.UNDECIDED) {
// The Registry filter can override the built-in white-list
return status;
}
}
if (filterInfo.depth() > REGISTRY_MAX_DEPTH) {
return ObjectInputFilter.Status.REJECTED;
}
Class<?> clazz = filterInfo.serialClass();
if (clazz != null) {
if (clazz.isArray()) {
if (filterInfo.arrayLength() >= 0 && filterInfo.arrayLength() > REGISTRY_MAX_ARRAY_SIZE) {
return ObjectInputFilter.Status.REJECTED;
}
do {
// Arrays are allowed depending on the component type
clazz = clazz.getComponentType();
} while (clazz.isArray());
}
if (clazz.isPrimitive()) {
// Arrays of primitives are allowed
return ObjectInputFilter.Status.ALLOWED;
}
if (String.class == clazz
|| java.lang.Number.class.isAssignableFrom(clazz)
|| Remote.class.isAssignableFrom(clazz)
|| java.lang.reflect.Proxy.class.isAssignableFrom(clazz)
|| UnicastRef.class.isAssignableFrom(clazz)
|| RMIClientSocketFactory.class.isAssignableFrom(clazz)
|| RMIServerSocketFactory.class.isAssignableFrom(clazz)
|| java.rmi.activation.ActivationID.class.isAssignableFrom(clazz)
|| java.rmi.server.UID.class.isAssignableFrom(clazz)) {
return ObjectInputFilter.Status.ALLOWED;
} else {
return ObjectInputFilter.Status.REJECTED;
}
}
return ObjectInputFilter.Status.UNDECIDED;
}
public DefaultObjectInputFilter(ObjectInputFilter filter) {
delegate = filter;
}
/**
* Exports the remote object to make it available to receive incoming
* calls, using the particular supplied port
* and {@linkplain ObjectInputFilter filter}.
*
* <p>The object is exported with a server socket
* created using the {@link RMISocketFactory} class.
*
* @param obj the remote object to be exported
* @param port the port to export the object on
* @param filter an ObjectInputFilter applied when deserializing invocation arguments;
* may be {@code null}
* @return remote object stub
* @exception RemoteException if export fails
* @since 9
*/
public static Remote exportObject(Remote obj, int port,
ObjectInputFilter filter)
throws RemoteException
{
return exportObject(obj, new UnicastServerRef(new LiveRef(port), filter));
}
/**
* Exports the remote object to make it available to receive incoming
* calls, using a transport specified by the given socket factory
* and {@linkplain ObjectInputFilter filter}.
*
* <p>Either socket factory may be {@code null}, in which case
* the corresponding client or server socket creation method of
* {@link RMISocketFactory} is used instead.
*
* @param obj the remote object to be exported
* @param port the port to export the object on
* @param csf the client-side socket factory for making calls to the
* remote object
* @param ssf the server-side socket factory for receiving remote calls
* @param filter an ObjectInputFilter applied when deserializing invocation arguments;
* may be {@code null}
* @return remote object stub
* @exception RemoteException if export fails
* @since 9
*/
public static Remote exportObject(Remote obj, int port,
RMIClientSocketFactory csf,
RMIServerSocketFactory ssf,
ObjectInputFilter filter)
throws RemoteException
{
return exportObject(obj, new UnicastServerRef2(port, csf, ssf, filter));
}
/**
* Creates a filter from the pattern.
*/
ObjectInputFilter createFilter2(String pattern);