1 /* 2 * Copyright (c) 2017, 2019, 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 sun.rmi.server.UnicastRef; 25 import sun.rmi.transport.LiveRef; 26 import sun.rmi.transport.tcp.TCPEndpoint; 27 28 import java.lang.reflect.InvocationHandler; 29 30 import java.lang.reflect.Proxy; 31 import java.net.InetAddress; 32 import java.rmi.AccessException; 33 import java.rmi.RemoteException; 34 import java.rmi.registry.LocateRegistry; 35 import java.rmi.registry.Registry; 36 import java.rmi.server.ObjID; 37 import java.rmi.server.RemoteObjectInvocationHandler; 38 import java.security.AccessController; 39 import java.security.PrivilegedAction; 40 import java.util.Set; 41 42 43 /* @test 44 * @bug 8218453 45 * @library ../../testlibrary 46 * @modules java.rmi/sun.rmi.registry:+open java.rmi/sun.rmi.server:+open 47 * java.rmi/sun.rmi.transport:+open java.rmi/sun.rmi.transport.tcp:+open 48 * @summary Verify that Registry rejects non-local access for bind, unbind, rebind. 49 * The test is manual because the (non-local) host running rmiregistry must be supplied as a property. 50 * @run main/othervm -Dregistry.host=localhost NonLocalSkeletonTest 51 */ 52 53 /* 54 * @test 55 * @library ../../testlibrary 56 * @modules java.rmi/sun.rmi.registry:+open java.rmi/sun.rmi.server:+open 57 * java.rmi/sun.rmi.transport:+open java.rmi/sun.rmi.transport.tcp:+open 58 * @summary Verify that Registry rejects non-local access for bind, unbind, rebind. 59 * The test is manual because the (non-local) host running rmiregistry must be supplied as a property. 60 * @run main/othervm/manual -Dregistry.host=rmi-registry-host NonLocalSkeletonTest 61 */ 62 63 /** 64 * Verify that access checks for Registry.bind(), .rebind(), and .unbind() 65 * are prevented on remote access to the registry. 66 * 67 * This test is a manual test and uses a standard rmiregistry running 68 * on a *different* host. 69 * The test verifies that the access check is performed *before* the object to be 70 * bound or rebound is deserialized. 71 * 72 * Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmiregistry}. 73 * It will not show any output. 74 * 75 * On the first host modify the @run command above to replace "rmi-registry-host" 76 * with the hostname or IP address of the different host and run the test with jtreg. 77 */ 78 public class NonLocalSkeletonTest { 79 main(String[] args)80 public static void main(String[] args) throws Exception { 81 String host = System.getProperty("registry.host"); 82 if (host == null || host.isEmpty()) { 83 throw new RuntimeException("supply a remote host with -Dregistry.host=hostname"); 84 } 85 86 // Check if running the test on a local system; it only applies to remote 87 String myHostName = InetAddress.getLocalHost().getHostName(); 88 Set<InetAddress> myAddrs = Set.of(InetAddress.getAllByName(myHostName)); 89 Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host)); 90 boolean isLocal = (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i)) 91 || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())); 92 93 int port; 94 if (isLocal) { 95 // Create a local Registry to use for the test 96 port = TestLibrary.getUnusedRandomPort(); 97 Registry registry = LocateRegistry.createRegistry(port); 98 System.out.printf("local registry port: %s%n", registry); 99 } else { 100 // Use regular rmi registry for non-local test 101 port = Registry.REGISTRY_PORT; 102 } 103 104 try { 105 106 Registry r = nonStaticRegistryProxy(host, port); 107 108 System.out.printf("RegistryRef: %s%n", r); 109 110 r.rebind("anyRef", r); 111 if (!isLocal) { 112 throw new RuntimeException("non-local bind should have failed to host: " + host); 113 } else { 114 System.out.printf("local rebind succeeded%n"); 115 } 116 } catch (RemoteException rex) { 117 if (!isLocal) { 118 assertIsAccessException(rex); 119 } else { 120 throw rex; 121 } 122 } 123 } 124 125 /* Returns a non-static proxy for the registry. 126 * Follows the form of sun.rmi.server.Util.createProxy. 127 * @param implClass the RegistryImpl 128 * @param clientRef the registry reference 129 **/ nonStaticRegistryProxy(String host, int port)130 static Registry nonStaticRegistryProxy(String host, int port) { 131 final ClassLoader loader = Registry.class.getClassLoader(); 132 final Class<?>[] interfaces = new Class<?>[]{Registry.class}; 133 134 LiveRef liveRef = new LiveRef(new ObjID(ObjID.REGISTRY_ID), 135 new TCPEndpoint(host, port, null, null), 136 false); 137 138 final InvocationHandler handler = new RemoteObjectInvocationHandler(new UnicastRef(liveRef)); 139 140 PrivilegedAction<Registry> action = () -> (Registry) Proxy.newProxyInstance(loader, 141 interfaces, handler); 142 return AccessController.doPrivileged(action); 143 } 144 145 /** 146 * Check the exception chain for the expected AccessException and message. 147 * @param ex the exception from the remote invocation. 148 */ assertIsAccessException(Throwable ex)149 private static void assertIsAccessException(Throwable ex) { 150 Throwable t = ex; 151 while (!(t instanceof AccessException) && t.getCause() != null) { 152 t = t.getCause(); 153 } 154 if (t instanceof AccessException) { 155 String msg = t.getMessage(); 156 int asIndex = msg.indexOf("Registry"); 157 int rrIndex = msg.indexOf("Registry.Registry"); // Obsolete error text 158 int disallowIndex = msg.indexOf("disallowed"); 159 int nonLocalHostIndex = msg.indexOf("non-local host"); 160 if (asIndex < 0 || 161 rrIndex != -1 || 162 disallowIndex < 0 || 163 nonLocalHostIndex < 0 ) { 164 throw new RuntimeException("exception message is malformed", t); 165 } 166 System.out.printf("Found expected AccessException: %s%n%n", t); 167 } else { 168 throw new RuntimeException("AccessException did not occur when expected", ex); 169 } 170 } 171 } 172