--- a/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Mon Aug 14 15:32:25 2017 +0530
+++ b/src/java.management.rmi/share/classes/javax/management/remote/rmi/RMIJRMPServerImpl.java Thu Sep 14 22:57:36 2017 +0200
@@ -26,6 +26,7 @@
package javax.management.remote.rmi;
import java.io.IOException;
+import java.io.ObjectInputFilter;
import java.rmi.NoSuchObjectException;
import java.rmi.Remote;
import java.rmi.RemoteException;
@@ -39,15 +40,13 @@
import com.sun.jmx.remote.internal.rmi.RMIExporter;
import com.sun.jmx.remote.util.EnvHelp;
-import java.io.ObjectStreamClass;
-import java.lang.reflect.Method;
-import java.util.ArrayList;
import java.util.Arrays;
-import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
import sun.reflect.misc.ReflectUtil;
-import sun.rmi.server.DeserializationChecker;
import sun.rmi.server.UnicastServerRef;
import sun.rmi.server.UnicastServerRef2;
+import sun.rmi.transport.LiveRef;
/**
* <p>An {@link RMIServer} object that is exported through JRMP and that
@@ -60,8 +59,6 @@
*/
public class RMIJRMPServerImpl extends RMIServerImpl {
- private final ExportedWrapper exportedWrapper;
-
/**
* <p>Creates a new {@link RMIServer} object that will be exported
* on the given port using the given socket factories.</p>
@@ -100,33 +97,48 @@
this.ssf = ssf;
this.env = (env == null) ? Collections.<String, Object>emptyMap() : env;
+ // This attribute was represented by RMIConnectorServer.CREDENTIALS_TYPES.
+ // This attribute is superceded by
+ // RMIConnectorServer.CREDENTIALS_FILTER_PATTERN.
+ // Retaining this for backward compatibility.
String[] credentialsTypes
- = (String[]) this.env.get(RMIConnectorServer.CREDENTIAL_TYPES);
- List<String> types = null;
- if (credentialsTypes != null) {
- types = new ArrayList<>();
- for (String type : credentialsTypes) {
- if (type == null) {
- throw new IllegalArgumentException("A credential type is null.");
- }
- ReflectUtil.checkPackageAccess(type);
- types.add(type);
- }
+ = (String[]) this.env.get("jmx.remote.rmi.server.credential.types");
+
+ String credentialsFilter
+ = (String) this.env.get(RMIConnectorServer.CREDENTIALS_FILTER_PATTERN);
+
+ // It is impossible for both attributes to be specified
+ if(credentialsTypes != null && credentialsFilter != null)
+ throw new IllegalArgumentException("Cannot specify both \""
+ + "jmx.remote.rmi.server.credential.types" + "\" and \""
+ + RMIConnectorServer.CREDENTIALS_FILTER_PATTERN + "\"");
+ else if(credentialsFilter != null){
+ cFilter = ObjectInputFilter.Config.createFilter(credentialsFilter);
+ allowedTypes = null;
}
- exportedWrapper = types != null ?
- new ExportedWrapper(this, types) :
- null;
+ else if (credentialsTypes != null) {
+ allowedTypes = Arrays.stream(credentialsTypes).filter(
+ s -> s!= null).collect(Collectors.toSet());
+ allowedTypes.stream().forEach(ReflectUtil::checkPackageAccess);
+ cFilter = this::newClientCheckInput;
+ } else {
+ allowedTypes = null;
+ cFilter = null;
+ }
+
+ String userJmxFilter =
+ (String) this.env.get(RMIConnectorServer.SERIAL_FILTER_PATTERN);
+ if(userJmxFilter != null && !userJmxFilter.isEmpty())
+ jmxRmiFilter = ObjectInputFilter.Config.createFilter(userJmxFilter);
+ else
+ jmxRmiFilter = null;
}
protected void export() throws IOException {
- if (exportedWrapper != null) {
- export(exportedWrapper);
- } else {
- export(this);
- }
+ export(this, cFilter);
}
- private void export(Remote obj) throws RemoteException {
+ private void export(Remote obj, ObjectInputFilter typeFilter) throws RemoteException {
final RMIExporter exporter =
(RMIExporter) env.get(RMIExporter.EXPORTER_ATTRIBUTE);
final boolean daemon = EnvHelp.isServerDaemon(env);
@@ -137,16 +149,14 @@
" cannot be used to specify an exporter!");
}
- if (daemon) {
+ if (exporter != null) {
+ exporter.exportObject(obj, port, csf, ssf, typeFilter);
+ } else {
if (csf == null && ssf == null) {
- new UnicastServerRef(port).exportObject(obj, null, true);
+ new UnicastServerRef(new LiveRef(port), typeFilter).exportObject(obj, null, daemon);
} else {
- new UnicastServerRef2(port, csf, ssf).exportObject(obj, null, true);
+ new UnicastServerRef2(port, csf, ssf, typeFilter).exportObject(obj, null, daemon);
}
- } else if (exporter != null) {
- exporter.exportObject(obj, port, csf, ssf);
- } else {
- UnicastRemoteObject.exportObject(obj, port, csf, ssf);
}
}
@@ -173,11 +183,7 @@
* RMIJRMPServerImpl has not been exported yet.
*/
public Remote toStub() throws IOException {
- if (exportedWrapper != null) {
- return RemoteObject.toStub(exportedWrapper);
- } else {
- return RemoteObject.toStub(this);
- }
+ return RemoteObject.toStub(this);
}
/**
@@ -207,7 +213,7 @@
RMIConnection client =
new RMIConnectionImpl(this, connectionId, getDefaultClassLoader(),
subject, env);
- export(client);
+ export(client, jmxRmiFilter);
return client;
}
@@ -224,56 +230,39 @@
* server failed.
*/
protected void closeServer() throws IOException {
- if (exportedWrapper != null) {
- unexport(exportedWrapper, true);
- } else {
- unexport(this, true);
+ unexport(this, true);
+ }
+
+ /**
+ * Check that a type in the remote invocation of {@link RMIServerImpl#newClient}
+ * is one of the {@code allowedTypes}.
+ *
+ * @param clazz the class; may be null
+ * @param size the size for arrays, otherwise is 0
+ * @param nObjectRefs the current number of object references
+ * @param depth the current depth
+ * @param streamBytes the current number of bytes consumed
+ * @return {@code ObjectInputFilter.Status.ALLOWED} if the class is allowed,
+ * otherwise {@code ObjectInputFilter.Status.REJECTED}
+ */
+ ObjectInputFilter.Status newClientCheckInput(ObjectInputFilter.FilterInfo filterInfo) {
+ ObjectInputFilter.Status status = ObjectInputFilter.Status.UNDECIDED;
+ if (allowedTypes != null && filterInfo.serialClass() != null) {
+ // If enabled, check type
+ String type = filterInfo.serialClass().getName();
+ if (allowedTypes.contains(type))
+ status = ObjectInputFilter.Status.ALLOWED;
+ else
+ status = ObjectInputFilter.Status.REJECTED;
}
+ return status;
}
private final int port;
private final RMIClientSocketFactory csf;
private final RMIServerSocketFactory ssf;
private final Map<String, ?> env;
-
- private static class ExportedWrapper implements RMIServer, DeserializationChecker {
- private final RMIServer impl;
- private final List<String> allowedTypes;
-
- private ExportedWrapper(RMIServer impl, List<String> credentialsTypes) {
- this.impl = impl;
- allowedTypes = credentialsTypes;
- }
-
- @Override
- public String getVersion() throws RemoteException {
- return impl.getVersion();
- }
-
- @Override
- public RMIConnection newClient(Object credentials) throws IOException {
- return impl.newClient(credentials);
- }
-
- @Override
- public void check(Method method, ObjectStreamClass descriptor,
- int paramIndex, int callID) {
- String type = descriptor.getName();
- if (!allowedTypes.contains(type)) {
- throw new ClassCastException("Unsupported type: " + type);
- }
- }
-
- @Override
- public void checkProxyClass(Method method, String[] ifaces,
- int paramIndex, int callID) {
- if (ifaces != null && ifaces.length > 0) {
- for (String iface : ifaces) {
- if (!allowedTypes.contains(iface)) {
- throw new ClassCastException("Unsupported type: " + iface);
- }
- }
- }
- }
- }
+ private final Set<String> allowedTypes;
+ private final ObjectInputFilter jmxRmiFilter;
+ private final ObjectInputFilter cFilter;
}