1 /* 2 * Copyright (c) 2016, 2017, 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.IOException; 25 import java.io.Serializable; 26 27 import java.rmi.AlreadyBoundException; 28 import java.rmi.MarshalledObject; 29 import java.rmi.NotBoundException; 30 import java.rmi.Remote; 31 import java.rmi.RemoteException; 32 import java.rmi.registry.LocateRegistry; 33 import java.rmi.registry.Registry; 34 import java.security.Security; 35 import java.util.Objects; 36 37 import org.testng.Assert; 38 import org.testng.TestNG; 39 import org.testng.annotations.BeforeSuite; 40 import org.testng.annotations.DataProvider; 41 import org.testng.annotations.Test; 42 43 /* 44 * @test 45 * @library /java/rmi/testlibrary 46 * @modules java.rmi/sun.rmi.registry 47 * java.rmi/sun.rmi.server 48 * java.rmi/sun.rmi.transport 49 * java.rmi/sun.rmi.transport.tcp 50 * @build TestLibrary 51 * @summary Test filters for the RMI Registry 52 * @run testng/othervm RegistryFilterTest 53 * @run testng/othervm 54 * -Dsun.rmi.registry.registryFilter=!java.lang.Long;!RegistryFilterTest$RejectableClass;maxdepth=19 55 * -Dtest.maxdepth=19 56 * RegistryFilterTest 57 * @run testng/othervm/policy=security.policy 58 * -Djava.security.properties=${test.src}/java.security-extra1 59 * RegistryFilterTest 60 */ 61 public class RegistryFilterTest { 62 private static Registry impl; 63 private static int port; 64 private static Registry registry; 65 66 static final int REGISTRY_MAX_DEPTH = 20; 67 68 static final int REGISTRY_MAX_ARRAY = 10000; 69 70 static final String registryFilter = 71 System.getProperty("sun.rmi.registry.registryFilter", 72 Security.getProperty("sun.rmi.registry.registryFilter")); 73 74 @DataProvider(name = "bindAllowed") 75 static Object[][] bindAllowedObjects() { 76 Object[][] objects = { 77 }; 78 return objects; 79 } 80 81 /** 82 * Data RMI Regiry bind test. 83 * - name 84 * - Object 85 * - true/false if object is blacklisted by a filter (implicit or explicit) 86 * @return array of test data 87 */ 88 @DataProvider(name = "bindData") 89 static Object[][] bindObjects() { 90 Object[][] data = { 91 { "byte[max]", new XX(new byte[REGISTRY_MAX_ARRAY]), false }, 92 { "String", new XX("now is the time"), false}, 93 { "String[]", new XX(new String[3]), false}, 94 { "Long[4]", new XX(new Long[4]), registryFilter != null }, 95 { "rej-byte[toobig]", new XX(new byte[REGISTRY_MAX_ARRAY + 1]), true }, 96 { "rej-MarshalledObject", createMarshalledObject(), true }, 97 { "rej-RejectableClass", new RejectableClass(), registryFilter != null}, 98 }; 99 return data; 100 } 101 102 static XX createMarshalledObject() { 103 try { 104 return new XX(new MarshalledObject<>(null)); 105 } catch (IOException ioe) { 106 return new XX(ioe); 107 } 108 } 109 110 @BeforeSuite 111 static void setupRegistry() { 112 try { 113 impl = TestLibrary.createRegistryOnEphemeralPort(); 114 port = TestLibrary.getRegistryPort(impl); 115 registry = LocateRegistry.getRegistry("localhost", port); 116 } catch (RemoteException ex) { 117 Assert.fail("initialization of registry", ex); 118 } 119 120 System.out.printf("RMI Registry filter: %s%n", registryFilter); 121 } 122 123 124 /* 125 * Test registry rejects an object with the max array size + 1. 126 */ 127 @Test(dataProvider="bindData") 128 public void simpleBind(String name, Remote obj, boolean blacklisted) throws RemoteException, AlreadyBoundException, NotBoundException { 129 try { 130 registry.bind(name, obj); 131 Assert.assertFalse(blacklisted, "Registry filter did not reject (but should have) "); 132 registry.unbind(name); 133 } catch (Exception rex) { 134 Assert.assertTrue(blacklisted, "Registry filter should not have rejected"); 135 } 136 } 137 138 /* 139 * Test registry rejects an object with a well known class 140 * if blacklisted in the security properties. 141 */ 142 @Test 143 public void simpleRejectableClass() throws RemoteException, AlreadyBoundException, NotBoundException { 144 RejectableClass r1 = null; 145 try { 146 String name = "reject1"; 147 r1 = new RejectableClass(); 148 registry.bind(name, r1); 149 registry.unbind(name); 150 Assert.assertNull(registryFilter, "Registry filter should have rejected"); 151 } catch (Exception rex) { 152 Assert.assertNotNull(registryFilter, "Registry filter should not have rejected"); 153 } 154 } 155 156 /* 157 * Test registry does not reject an object with depth at the built-in limit. 158 */ 159 @Test 160 public void simpleDepthBuiltinNonRejectable() throws RemoteException, AlreadyBoundException, NotBoundException { 161 int depthOverride = Integer.getInteger("test.maxdepth", REGISTRY_MAX_DEPTH); 162 depthOverride = Math.min(depthOverride, REGISTRY_MAX_DEPTH); 163 System.out.printf("overrideDepth: %d, filter: %s%n", depthOverride, registryFilter); 164 try { 165 String name = "reject2"; 166 DepthRejectableClass r1 = DepthRejectableClass.create(depthOverride); 167 registry.bind(name, r1); 168 registry.unbind(name); 169 } catch (Exception rex) { 170 Assert.fail("Registry filter should not have rejected depth: " 171 + depthOverride); 172 } 173 } 174 175 /* 176 * Test registry rejects an object with depth at the limit + 1. 177 */ 178 @Test 179 public void simpleDepthRejectable() throws RemoteException, AlreadyBoundException, NotBoundException { 180 int depthOverride = Integer.getInteger("test.maxdepth", REGISTRY_MAX_DEPTH); 181 depthOverride = Math.min(depthOverride, REGISTRY_MAX_DEPTH); 182 System.out.printf("overrideDepth: %d, filter: %s%n", depthOverride, registryFilter); 183 try { 184 String name = "reject3"; 185 DepthRejectableClass r1 = DepthRejectableClass.create(depthOverride + 1); 186 registry.bind(name, r1); 187 Assert.fail("Registry filter should have rejected depth: " + depthOverride + 1); 188 } catch (Exception rex) { 189 // Rejection expected 190 } 191 } 192 193 /** 194 * A simple Serializable Remote object that is passed by value. 195 * It and its contents are checked by the Registry serial filter. 196 */ 197 static class XX implements Serializable, Remote { 198 private static final long serialVersionUID = 362498820763181265L; 199 200 final Object obj; 201 202 XX(Object obj) { 203 this.obj = obj; 204 } 205 206 public String toString() { 207 return super.toString() + "//" + Objects.toString(obj); 208 } 209 } 210 211 /** 212 * A simple Serializable Remote object that is passed by value. 213 * It and its contents are checked by the Registry serial filter. 214 */ 215 static class RejectableClass implements Serializable, Remote { 216 private static final long serialVersionUID = 362498820763181264L; 217 218 RejectableClass() {} 219 } 220 221 /** 222 * A simple Serializable Remote object that is passed by value. 223 * It and its contents are checked by the Registry serial filter. 224 */ 225 static class DepthRejectableClass implements Serializable, Remote { 226 private static final long serialVersionUID = 362498820763181264L; 227 private final DepthRejectableClass next; 228 229 private DepthRejectableClass(DepthRejectableClass next) { 230 this.next = next; 231 } 232 233 static DepthRejectableClass create(int depth) { 234 DepthRejectableClass next = new DepthRejectableClass(null); 235 for (int i = 1; i < depth; i++) { 236 next = new DepthRejectableClass(next); 237 } 238 return next; 239 } 240 } 241 242 }