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.ObjectInputStream;
27 import java.io.Serializable;
28 import java.security.Security;
29 
30 import sun.misc.ObjectInputFilter;
31 
32 import org.testng.annotations.BeforeClass;
33 import org.testng.annotations.DataProvider;
34 import org.testng.annotations.Test;
35 
36 import static org.testng.Assert.assertTrue;
37 import static org.testng.Assert.fail;
38 
39 /* @test
40  * @build MixedFiltersTest SerialFilterTest
41  * @run testng/othervm -Djdk.serialFilter=!java.**;!java.lang.Long;maxdepth=5;maxarray=5;maxbytes=90;maxrefs=5          MixedFiltersTest
42  * @run testng/othervm -Djdk.serialFilter=java.**;java.lang.Long;maxdepth=1000;maxarray=1000;maxbytes=1000;maxrefs=1000 MixedFiltersTest
43  *
44  * @summary Test that when both global filter and specific filter are set,
45  *          global filter will not affect specific filter.
46  */
47 
48 public class MixedFiltersTest implements Serializable {
49 
50     private static final long serialVersionUID = 1234567890L;
51 
52 
53     boolean globalRejected;
54 
55     @BeforeClass
setup()56     public void setup() {
57         String pattern = System.getProperty("jdk.serialFilter",
58                 Security.getProperty("jdk.serialFilter"));
59         globalRejected = pattern.startsWith("!");
60     }
61 
62     @DataProvider(name="RejectedInGlobal")
rejectedInGlobal()63     Object[][] rejectedInGlobal() {
64         if (!globalRejected) {
65             return new Object[0][];
66         }
67         return new Object[][] {
68                 new Object[] { Long.MAX_VALUE, "java.**" },
69                 new Object[] { Long.MAX_VALUE, "java.lang.Long" },
70                 new Object[] { SerialFilterTest.genTestObject("java.lang.**", true), "java.lang.**" },
71                 new Object[] { SerialFilterTest.genTestObject("maxdepth=10", true), "maxdepth=100" },
72                 new Object[] { SerialFilterTest.genTestObject("maxarray=10", true), "maxarray=100" },
73                 new Object[] { SerialFilterTest.genTestObject("maxbytes=100", true), "maxbytes=1000" },
74                 new Object[] { SerialFilterTest.genTestObject("maxrefs=10", true), "maxrefs=100" },
75         };
76     }
77 
78     /**
79      * Test:
80      *   "global filter reject" + "specific ObjectInputStream filter is empty" => should reject
81      *   "global filter reject" + "specific ObjectInputStream filter allow"    => should allow
82      */
83     @Test(dataProvider="RejectedInGlobal")
testRejectedInGlobal(Object toDeserialized, String pattern)84     public void testRejectedInGlobal(Object toDeserialized, String pattern) throws Exception {
85         byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
86         try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
87                 ObjectInputStream ois = new ObjectInputStream(bais)) {
88             Object o = ois.readObject();
89             fail("filter should have thrown an exception");
90         } catch (InvalidClassException expected) { }
91 
92         ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
93         try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
94                 ObjectInputStream ois = new ObjectInputStream(bais)) {
95             ObjectInputFilter.Config.setObjectInputFilter(ois, filter);
96             Object o = ois.readObject();
97         }
98     }
99 
100     @DataProvider(name="AllowedInGlobal")
allowedInGlobal()101     Object[][] allowedInGlobal() {
102         if (globalRejected) {
103             return new Object[0][];
104         }
105 
106         return new Object[][] {
107                 new Object[] { Long.MAX_VALUE, "!java.**" },
108                 new Object[] { Long.MAX_VALUE, "!java.lang.Long" },
109                 new Object[] { SerialFilterTest.genTestObject("java.lang.**", true), "!java.lang.**" },
110                 new Object[] { SerialFilterTest.genTestObject("maxdepth=10", true), "maxdepth=5" },
111                 new Object[] { SerialFilterTest.genTestObject("maxarray=10", true), "maxarray=5" },
112                 new Object[] { SerialFilterTest.genTestObject("maxbytes=100", true), "maxbytes=5" },
113                 new Object[] { SerialFilterTest.genTestObject("maxrefs=10", true), "maxrefs=5" },
114             };
115     }
116 
117     /**
118      * Test:
119      *   "global filter allow" + "specific ObjectInputStream filter is empty" => should allow
120      *   "global filter allow" + "specific ObjectInputStream filter reject"   => should reject
121      */
122     @Test(dataProvider="AllowedInGlobal")
testAllowedInGlobal(Object toDeserialized, String pattern)123     public void testAllowedInGlobal(Object toDeserialized, String pattern) throws Exception {
124         byte[] bytes = SerialFilterTest.writeObjects(toDeserialized);
125         try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
126                 ObjectInputStream ois = new ObjectInputStream(bais)) {
127             Object o = ois.readObject();
128         }
129 
130         ObjectInputFilter filter = ObjectInputFilter.Config.createFilter(pattern);
131         try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
132                 ObjectInputStream ois = new ObjectInputStream(bais)) {
133             ObjectInputFilter.Config.setObjectInputFilter(ois, filter);
134             Object o = ois.readObject();
135             assertTrue(false, "filter should have thrown an exception");
136         } catch (InvalidClassException expected) { }
137     }
138 }
139