1 /*
2  * Copyright (c) 2016, 2018, 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.InvalidClassException;
25 import java.io.ObjectInputFilter;
26 import java.io.Serializable;
27 
28 import java.rmi.Remote;
29 import java.rmi.RemoteException;
30 import java.rmi.UnmarshalException;
31 
32 import java.util.Objects;
33 
34 import sun.rmi.server.UnicastServerRef;
35 import sun.rmi.server.UnicastServerRef2;
36 import sun.rmi.transport.LiveRef;
37 
38 import org.testng.Assert;
39 import org.testng.annotations.DataProvider;
40 import org.testng.annotations.Test;
41 
42 
43 /*
44  * @test
45  * @modules java.rmi/sun.rmi.registry
46  *          java.rmi/sun.rmi.server
47  *          java.rmi/sun.rmi.transport
48  *          java.rmi/sun.rmi.transport.tcp
49  * @run testng/othervm FilterUSRTest
50  * @summary Check objects exported with ObjectInputFilters via internal UnicastServerRef(2)
51  */
52 public class FilterUSRTest {
53 
54     /**
55      * Data to test serialFilter call counts.
56      * - name
57      * - Object
58      * - expected count of calls to checkInput.
59      *
60      * @return array of test data
61      */
62     @DataProvider(name = "bindData")
bindObjects()63     static Object[][] bindObjects() {
64         Object[][] data = {
65                 {"SimpleString", "SimpleString", 0},
66                 {"String", new XX("now is the time"), 1},
67                 {"String[]", new XX(new String[3]), 3},
68                 {"Long[4]", new XX(new Long[4]), 3},
69                 {"RejectME", new XX(new RejectME()), -1},
70         };
71         return data;
72     }
73 
74     /*
75      * Test exporting an object with a serialFilter using UnicastServerRef.exportObject().
76      * Send some objects and check the number of calls to the serialFilter.
77      */
78     @Test(dataProvider = "bindData")
UnicastServerRef(String name, Object obj, int expectedFilterCount)79     public void UnicastServerRef(String name, Object obj, int expectedFilterCount) throws RemoteException {
80         try {
81             RemoteImpl impl = RemoteImpl.create();
82             UnicastServerRef ref = new UnicastServerRef(new LiveRef(0), impl.checker);
83 
84             Echo client = (Echo) ref.exportObject(impl, null, false);
85 
86             int count = client.filterCount(obj);
87             System.out.printf("count: %d, obj: %s%n", count, obj);
88             Assert.assertEquals(count, expectedFilterCount, "wrong number of filter calls");
89         } catch (RemoteException rex) {
90             if (expectedFilterCount == -1 &&
91                     UnmarshalException.class.equals(rex.getCause().getClass()) &&
92                     InvalidClassException.class.equals(rex.getCause().getCause().getClass())) {
93                 return; // normal expected exception
94             }
95             rex.printStackTrace();
96             Assert.fail("unexpected remote exception", rex);
97         } catch (Exception ex) {
98             Assert.fail("unexpected exception", ex);
99         }
100     }
101 
102     /*
103      * Test exporting an object with a serialFilter using UnicastServerRef2.exportObject()
104      * with explicit (but null) SocketFactories.
105      * Send some objects and check the number of calls to the serialFilter.
106      */
107     @Test(dataProvider = "bindData")
UnicastServerRef2(String name, Object obj, int expectedFilterCount)108     public void UnicastServerRef2(String name, Object obj, int expectedFilterCount) throws RemoteException {
109         try {
110             RemoteImpl impl = RemoteImpl.create();
111             UnicastServerRef2 ref = new UnicastServerRef2(0, null, null, impl.checker);
112 
113             Echo client = (Echo) ref.exportObject(impl, null, false);
114 
115             int count = client.filterCount(obj);
116             System.out.printf("count: %d, obj: %s%n", count, obj);
117             Assert.assertEquals(count, expectedFilterCount, "wrong number of filter calls");
118         } catch (RemoteException rex) {
119             if (expectedFilterCount == -1 &&
120                     UnmarshalException.class.equals(rex.getCause().getClass()) &&
121                     InvalidClassException.class.equals(rex.getCause().getCause().getClass())) {
122                 return; // normal expected exception
123             }
124             rex.printStackTrace();
125             Assert.fail("unexpected remote exception", rex);
126         } catch (Exception rex) {
127             Assert.fail("unexpected exception", rex);
128         }
129     }
130 
131     /**
132      * A simple Serializable holding an object that is passed by value.
133      * It and its contents are checked by the filter.
134      */
135     static class XX implements Serializable {
136         private static final long serialVersionUID = 362498820763181265L;
137 
138         final Object obj;
139 
XX(Object obj)140         XX(Object obj) {
141             this.obj = obj;
142         }
143 
toString()144         public String toString() {
145             return super.toString() + "//" + Objects.toString(obj);
146         }
147     }
148 
149     interface Echo extends Remote {
filterCount(Object obj)150         int filterCount(Object obj) throws RemoteException;
151     }
152 
153     /**
154      * This remote object just counts the calls to the serialFilter
155      * and returns it.  The caller can check the number against
156      * what was expected for the object passed as an argument.
157      * A new RemoteImpl is used for each test so the count starts at zero again.
158      */
159     static class RemoteImpl implements Echo {
160 
161         private static final long serialVersionUID = 1L;
162 
163         transient Checker checker;
164 
create()165         static RemoteImpl create() throws RemoteException {
166             RemoteImpl impl = new RemoteImpl(new Checker());
167             return impl;
168         }
169 
RemoteImpl(Checker checker)170         private RemoteImpl(Checker checker) throws RemoteException {
171             this.checker = checker;
172         }
173 
filterCount(Object obj)174         public int filterCount(Object obj) throws RemoteException {
175             return checker.count();
176         }
177 
178     }
179 
180     /**
181      * A ObjectInputFilter that just counts when it is called.
182      */
183     static class Checker implements ObjectInputFilter {
184         int count;
185 
186         @Override
checkInput(ObjectInputFilter.FilterInfo info)187         public Status checkInput(ObjectInputFilter.FilterInfo info) {
188             if (info.serialClass() == RejectME.class) {
189                 return Status.REJECTED;
190             }
191             count++;
192             return Status.UNDECIDED;
193         }
194 
count()195         public int count() {
196             return count;
197         }
198     }
199 
200     /**
201      * A class to be rejected by the filter.
202      */
203     static class RejectME implements Serializable {
204         private static final long serialVersionUID = 2L;
205     }
206 
207 }
208