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