1 /*
2  * Copyright (c) 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.net.InetAddress;
25 import java.rmi.AccessException;
26 import java.rmi.activation.ActivationSystem;
27 import java.rmi.registry.LocateRegistry;
28 import java.rmi.registry.Registry;
29 import java.util.Set;
30 
31 /*
32  * @test
33  * @bug 8174770
34  * @summary Verify that ActivationSystem rejects non-local access.
35  *    The test is manual because the (non-local) host running rmid must be supplied as a property.
36  * @run main/manual/othervm -Dactivation.host=rmid-host NonLocalActivationTest
37  */
38 
39 /**
40  * Lookup the ActivationSystem on a different host and invoke its remote interface methods.
41  * They should all throw an exception, non-local access is prohibited.
42  *
43  * This test is a manual test and uses rmid running on a *different* host.
44  * The default port (1098) for the Activation System is ok and expected.
45  * Login or ssh to the different host and invoke {@code $JDK_HOME/bin/rmid}.
46  * It will not show any output.
47  *
48  * On the first host modify the @run command above to replace "rmid-host"
49  * with the hostname or IP address of the different host and run the test with jtreg.
50  */
51 public class NonLocalActivationTest
52 {
main(String[] args)53     public static void main(String[] args) throws Exception {
54 
55         String host = System.getProperty("activation.host");
56         if (host == null || host.isEmpty()) {
57             throw new RuntimeException("Specify host with system property: -Dactivation.host=<host>");
58         }
59 
60         // Check if running the test on a local system; it only applies to remote
61         String myHostName = InetAddress.getLocalHost().getHostName();
62         Set<InetAddress> myAddrs = Set.of(InetAddress.getAllByName(myHostName));
63         Set<InetAddress> hostAddrs = Set.of(InetAddress.getAllByName(host));
64         if (hostAddrs.stream().anyMatch(i -> myAddrs.contains(i))
65                 || hostAddrs.stream().anyMatch(h -> h.isLoopbackAddress())) {
66             throw new RuntimeException("Error: property 'activation.host' must not be the local host%n");
67         }
68 
69         // Locate the registry operated by the ActivationSystem
70         // Test SystemRegistryImpl
71         Registry registry = LocateRegistry.getRegistry(host, ActivationSystem.SYSTEM_PORT);
72         try {
73             // Verify it is an ActivationSystem registry
74             registry.lookup("java.rmi.activation.ActivationSystem");
75         } catch (Exception nf) {
76             throw new RuntimeException("Not a ActivationSystem registry, does not contain java.rmi.activation.ActivationSystem", nf);
77         }
78 
79         try {
80             registry.bind("foo", null);
81             throw new RuntimeException("Remote access should not succeed for method: bind");
82         } catch (Exception e) {
83             assertIsAccessException(e, "Registry.bind");
84         }
85 
86         try {
87             registry.rebind("foo", null);
88             throw new RuntimeException("Remote access should not succeed for method: rebind");
89         } catch (Exception e) {
90             assertIsAccessException(e, "Registry.rebind");
91         }
92 
93         try {
94             registry.unbind("foo");
95             throw new RuntimeException("Remote access should not succeed for method: unbind");
96         } catch (Exception e) {
97             assertIsAccessException(e, "Registry.unbind");
98         }
99 
100 
101         // Locate the ActivationSystem on the specified host and default port.
102         // Test each of the ActivationSystem methods
103         ActivationSystem as = (ActivationSystem) registry.lookup("java.rmi.activation.ActivationSystem");
104 
105         // Argument is not material, access check is before arg processing
106 
107         try {
108             as.registerGroup(null);
109         } catch (Exception aex) {
110             assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
111         }
112 
113         try {
114             as.getActivationDesc(null);
115         } catch (Exception aex) {
116             assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
117         }
118 
119         try {
120             as.getActivationGroupDesc(null);
121         } catch (Exception aex) {
122             assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
123         }
124 
125         try {
126             as.registerObject(null);
127         } catch (Exception aex) {
128             assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
129         }
130 
131         try {
132             as.unregisterGroup(null);
133         } catch (Exception aex) {
134             assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
135         }
136 
137         try {
138             as.unregisterObject(null);
139         } catch (Exception aex) {
140             assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
141         }
142 
143         try {
144             as.setActivationDesc(null, null);
145         } catch (Exception aex) {
146             assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
147         }
148 
149         try {
150             as.setActivationGroupDesc(null, null);
151         } catch (Exception aex) {
152             assertIsAccessException(aex, "ActivationSystem.nonLocalAccess");
153         }
154     }
155 
156     /**
157      * Check the exception chain for the expected AccessException and message.
158      * @param ex the exception from the remote invocation.
159      */
assertIsAccessException(Exception ex, String msg1)160     private static void assertIsAccessException(Exception ex, String msg1) {
161         Throwable t = ex;
162         System.out.println();
163         while (!(t instanceof AccessException) && t.getCause() != null) {
164             t = t.getCause();
165         }
166         if (t instanceof AccessException) {
167             String msg = t.getMessage();
168             int asIndex = msg.indexOf(msg1);
169             int disallowIndex = msg.indexOf("disallowed");
170             int nonLocalHostIndex = msg.indexOf("non-local host");
171             if (asIndex < 0 ||
172                     disallowIndex < 0 ||
173                     nonLocalHostIndex < 0 ) {
174                 throw new RuntimeException("exception message is malformed", t);
175             }
176             System.out.printf("Found expected AccessException: %s%n", t);
177         } else {
178             throw new RuntimeException("AccessException did not occur", ex);
179         }
180     }
181 }
182