1 /*
2  * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 import java.io.ByteArrayInputStream;
25 import java.io.InvalidClassException;
26 import java.io.ObjectInputFilter;
27 import java.io.ObjectInputStream;
28 import java.io.Serializable;
29 import java.security.Security;
30 
31 import org.testng.annotations.BeforeClass;
32 import org.testng.annotations.DataProvider;
33 import org.testng.annotations.Test;
34 
35 import static org.testng.Assert.assertTrue;
36 import static org.testng.Assert.fail;
37 
38 /* @test
39  * @build MixedFiltersTest SerialFilterTest
40  * @run testng/othervm -Djdk.serialFilter=!java.**;!java.lang.Long;maxdepth=5;maxarray=5;maxbytes=90;maxrefs=5          MixedFiltersTest
41  * @run testng/othervm -Djdk.serialFilter=java.**;java.lang.Long;maxdepth=1000;maxarray=1000;maxbytes=1000;maxrefs=1000 MixedFiltersTest
42  *
43  * @summary Test that when both global filter and specific filter are set,
44  *          global filter will not affect specific filter.
45  */
46 
47 public class MixedFiltersTest implements Serializable {
48 
49     private static final long serialVersionUID = 1234567890L;
50 
51 
52     boolean globalRejected;
53 
54     @BeforeClass
setup()55     public void setup() {
56         String pattern = System.getProperty("jdk.serialFilter",
57                 Security.getProperty("jdk.serialFilter"));
58         globalRejected = pattern.startsWith("!");
59     }
60 
61     @DataProvider(name="RejectedInGlobal")
rejectedInGlobal()62     Object[][] rejectedInGlobal() {
63         if (!globalRejected) {
64             return new Object[0][];
65         }
66         return new Object[][] {
67                 new Object[] { Long.MAX_VALUE, "java.**" },
68                 new Object[] { Long.MAX_VALUE, "java.lang.Long" },
69                 new Object[] { SerialFilterTest.genTestObject("java.lang.**", true), "java.lang.**" },
70                 new Object[] { SerialFilterTest.genTestObject("maxdepth=10", true), "maxdepth=100" },
71                 new Object[] { SerialFilterTest.genTestObject("maxarray=10", true), "maxarray=100" },
72                 new Object[] { SerialFilterTest.genTestObject("maxbytes=100", true), "maxbytes=1000" },
73                 new Object[] { SerialFilterTest.genTestObject("maxrefs=10", true), "maxrefs=100" },
74         };
75     }
76 
77     /**
78      * Test:
79      *   "global filter reject" + "specific ObjectInputStream filter is empty" => should reject
80      *   "global filter reject" + "specific ObjectInputStream filter allow"    => should allow
81      */
82     @Test(dataProvider="RejectedInGlobal")
testRejectedInGlobal(Object toDeserialized, String pattern)83     public void testRejectedInGlobal(Object toDeserialized, String pattern) throws Exception {
84         byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
85         try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
86                 ObjectInputStream ois = new ObjectInputStream(bais)) {
87             Object o = ois.readObject();
88             fail("filter should have thrown an exception");
89         } catch (InvalidClassException expected) { }
90 
91         ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
92         try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
93                 ObjectInputStream ois = new ObjectInputStream(bais)) {
94             ois.setObjectInputFilter(filter);
95             Object o = ois.readObject();
96         }
97     }
98 
99     @DataProvider(name="AllowedInGlobal")
allowedInGlobal()100     Object[][] allowedInGlobal() {
101         if (globalRejected) {
102             return new Object[0][];
103         }
104 
105         return new Object[][] {
106                 new Object[] { Long.MAX_VALUE, "!java.**" },
107                 new Object[] { Long.MAX_VALUE, "!java.lang.Long" },
108                 new Object[] { SerialFilterTest.genTestObject("java.lang.**", true), "!java.lang.**" },
109                 new Object[] { SerialFilterTest.genTestObject("maxdepth=10", true), "maxdepth=5" },
110                 new Object[] { SerialFilterTest.genTestObject("maxarray=10", true), "maxarray=5" },
111                 new Object[] { SerialFilterTest.genTestObject("maxbytes=100", true), "maxbytes=5" },
112                 new Object[] { SerialFilterTest.genTestObject("maxrefs=10", true), "maxrefs=5" },
113             };
114     }
115 
116     /**
117      * Test:
118      *   "global filter allow" + "specific ObjectInputStream filter is empty" => should allow
119      *   "global filter allow" + "specific ObjectInputStream filter reject"   => should reject
120      */
121     @Test(dataProvider="AllowedInGlobal")
testAllowedInGlobal(Object toDeserialized, String pattern)122     public void testAllowedInGlobal(Object toDeserialized, String pattern) throws Exception {
123         byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
124         try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
125                 ObjectInputStream ois = new ObjectInputStream(bais)) {
126             Object o = ois.readObject();
127         }
128 
129         ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
130         try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
131                 ObjectInputStream ois = new ObjectInputStream(bais)) {
132             ois.setObjectInputFilter(filter);
133             Object o = ois.readObject();
134             assertTrue(false, "filter should have thrown an exception");
135         } catch (InvalidClassException expected) { }
136     }
137 }
138