Path: blob/master/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java
41162 views
/*1* Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425package javax.management.remote.rmi;2627import java.io.IOException;28import java.io.ObjectInputFilter;29import java.rmi.NoSuchObjectException;30import java.rmi.Remote;31import java.rmi.RemoteException;32import java.rmi.server.RMIClientSocketFactory;33import java.rmi.server.RMIServerSocketFactory;34import java.rmi.server.UnicastRemoteObject;35import java.rmi.server.RemoteObject;36import java.util.Map;37import java.util.Collections;38import javax.security.auth.Subject;3940import com.sun.jmx.remote.internal.rmi.RMIExporter;41import com.sun.jmx.remote.util.EnvHelp;42import java.util.Arrays;43import java.util.Set;44import java.util.stream.Collectors;45import sun.reflect.misc.ReflectUtil;46import sun.rmi.server.UnicastServerRef;47import sun.rmi.server.UnicastServerRef2;48import sun.rmi.transport.LiveRef;4950/**51* <p>An {@link RMIServer} object that is exported through JRMP and that52* creates client connections as RMI objects exported through JRMP.53* User code does not usually reference this class directly.</p>54*55* @see RMIServerImpl56*57* @since 1.558*/59public class RMIJRMPServerImpl extends RMIServerImpl {6061/**62* <p>Creates a new {@link RMIServer} object that will be exported63* on the given port using the given socket factories.</p>64*65* @param port the port on which this object and the {@link66* RMIConnectionImpl} objects it creates will be exported. Can be67* zero, to indicate any available port.68*69* @param csf the client socket factory for the created RMI70* objects. Can be null.71*72* @param ssf the server socket factory for the created RMI73* objects. Can be null.74*75* @param env the environment map. Can be null.76*77* @exception IOException if the {@link RMIServer} object78* cannot be created.79*80* @exception IllegalArgumentException if <code>port</code> is81* negative.82*/83public RMIJRMPServerImpl(int port,84RMIClientSocketFactory csf,85RMIServerSocketFactory ssf,86Map<String,?> env)87throws IOException {8889super(env);9091if (port < 0)92throw new IllegalArgumentException("Negative port: " + port);9394this.port = port;95this.csf = csf;96this.ssf = ssf;97this.env = (env == null) ? Collections.<String, Object>emptyMap() : env;9899// This attribute was represented by RMIConnectorServer.CREDENTIALS_TYPES.100// This attribute is superceded by101// RMIConnectorServer.CREDENTIALS_FILTER_PATTERN.102// Retaining this for backward compatibility.103String[] credentialsTypes104= (String[]) this.env.get("jmx.remote.rmi.server.credential.types");105106String credentialsFilter107= (String) this.env.get(RMIConnectorServer.CREDENTIALS_FILTER_PATTERN);108109// It is impossible for both attributes to be specified110if(credentialsTypes != null && credentialsFilter != null)111throw new IllegalArgumentException("Cannot specify both \""112+ "jmx.remote.rmi.server.credential.types" + "\" and \""113+ RMIConnectorServer.CREDENTIALS_FILTER_PATTERN + "\"");114else if(credentialsFilter != null){115cFilter = ObjectInputFilter.Config.createFilter(credentialsFilter);116allowedTypes = null;117}118else if (credentialsTypes != null) {119allowedTypes = Arrays.stream(credentialsTypes).filter(120s -> s!= null).collect(Collectors.toSet());121allowedTypes.stream().forEach(ReflectUtil::checkPackageAccess);122cFilter = this::newClientCheckInput;123} else {124allowedTypes = null;125cFilter = null;126}127128String userJmxFilter =129(String) this.env.get(RMIConnectorServer.SERIAL_FILTER_PATTERN);130if(userJmxFilter != null && !userJmxFilter.isEmpty())131jmxRmiFilter = ObjectInputFilter.Config.createFilter(userJmxFilter);132else133jmxRmiFilter = null;134}135136protected void export() throws IOException {137export(this, cFilter);138}139140private void export(Remote obj, ObjectInputFilter typeFilter) throws RemoteException {141final RMIExporter exporter =142(RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);143final boolean daemon = EnvHelp.isServerDaemon(env);144145if (daemon && exporter != null) {146throw new IllegalArgumentException("If "+EnvHelp.JMX_SERVER_DAEMON+147" is specified as true, "+RMIExporter.EXPORTER_ATTRIBUTE+148" cannot be used to specify an exporter!");149}150151if (exporter != null) {152exporter.exportObject(obj, port, csf, ssf, typeFilter);153} else {154if (csf == null && ssf == null) {155new UnicastServerRef(new LiveRef(port), typeFilter).exportObject(obj, null, daemon);156} else {157new UnicastServerRef2(port, csf, ssf, typeFilter).exportObject(obj, null, daemon);158}159}160}161162private void unexport(Remote obj, boolean force)163throws NoSuchObjectException {164RMIExporter exporter =165(RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);166if (exporter == null)167UnicastRemoteObject.unexportObject(obj, force);168else169exporter.unexportObject(obj, force);170}171172protected String getProtocol() {173return "rmi";174}175176/**177* <p>Returns a serializable stub for this {@link RMIServer} object.</p>178*179* @return a serializable stub.180*181* @exception IOException if the stub cannot be obtained - e.g the182* RMIJRMPServerImpl has not been exported yet.183*/184public Remote toStub() throws IOException {185return RemoteObject.toStub(this);186}187188/**189* <p>Creates a new client connection as an RMI object exported190* through JRMP. The port and socket factories for the new191* {@link RMIConnection} object are the ones supplied192* to the <code>RMIJRMPServerImpl</code> constructor.</p>193*194* @param connectionId the ID of the new connection. Every195* connection opened by this connector server will have a196* different id. The behavior is unspecified if this parameter is197* null.198*199* @param subject the authenticated subject. Can be null.200*201* @return the newly-created <code>RMIConnection</code>.202*203* @exception IOException if the new {@link RMIConnection}204* object cannot be created or exported.205*/206protected RMIConnection makeClient(String connectionId, Subject subject)207throws IOException {208209if (connectionId == null)210throw new NullPointerException("Null connectionId");211212RMIConnection client =213new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(),214subject, env);215export(client, jmxRmiFilter);216return client;217}218219protected void closeClient(RMIConnection client) throws IOException {220unexport(client, true);221}222223/**224* <p>Called by {@link #close()} to close the connector server by225* unexporting this object. After returning from this method, the226* connector server must not accept any new connections.</p>227*228* @exception IOException if the attempt to close the connector229* server failed.230*/231protected void closeServer() throws IOException {232unexport(this, true);233}234235/**236* Check that a type in the remote invocation of {@link RMIServerImpl#newClient}237* is one of the {@code allowedTypes}.238*239* @param clazz the class; may be null240* @param size the size for arrays, otherwise is 0241* @param nObjectRefs the current number of object references242* @param depth the current depth243* @param streamBytes the current number of bytes consumed244* @return {@code ObjectInputFilter.Status.ALLOWED} if the class is allowed,245* otherwise {@code ObjectInputFilter.Status.REJECTED}246*/247ObjectInputFilter.Status newClientCheckInput(ObjectInputFilter.FilterInfo filterInfo) {248ObjectInputFilter.Status status = ObjectInputFilter.Status.UNDECIDED;249if (allowedTypes != null && filterInfo.serialClass() != null) {250// If enabled, check type251String type = filterInfo.serialClass().getName();252if (allowedTypes.contains(type))253status = ObjectInputFilter.Status.ALLOWED;254else255status = ObjectInputFilter.Status.REJECTED;256}257return status;258}259260private final int port;261private final RMIClientSocketFactory csf;262private final RMIServerSocketFactory ssf;263private final Map<String, ?> env;264private final Set<String> allowedTypes;265private final ObjectInputFilter jmxRmiFilter;266private final ObjectInputFilter cFilter;267}268269270