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