Path: blob/master/test/jdk/javax/management/remote/mandatory/notif/NotificationAccessControllerTest.java
41155 views
/*1* Copyright (c) 2005, 2015, 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.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* @test25* @bug 510672126* @summary Check the NotificationAccessController methods are properly called.27* @author Luis-Miguel Alventosa28* @modules java.management.rmi29* java.management/com.sun.jmx.remote.security30* @run clean NotificationAccessControllerTest31* @run build NotificationAccessControllerTest32* @run main NotificationAccessControllerTest33*/3435import com.sun.jmx.remote.security.NotificationAccessController;36import java.util.ArrayList;37import java.util.Collections;38import java.util.HashMap;39import java.util.List;40import java.util.Map;41import java.util.concurrent.CopyOnWriteArrayList;42import java.util.concurrent.Semaphore;43import javax.management.MBeanServer;44import javax.management.MBeanServerConnection;45import javax.management.MBeanServerFactory;46import javax.management.Notification;47import javax.management.NotificationBroadcasterSupport;48import javax.management.NotificationListener;49import javax.management.ObjectName;50import javax.management.remote.JMXAuthenticator;51import javax.management.remote.JMXConnector;52import javax.management.remote.JMXConnectorFactory;53import javax.management.remote.JMXConnectorServer;54import javax.management.remote.JMXConnectorServerFactory;55import javax.management.remote.JMXPrincipal;56import javax.management.remote.JMXServiceURL;57import javax.security.auth.Subject;5859public class NotificationAccessControllerTest {6061public class NAC implements NotificationAccessController {62private final boolean throwException;63public NAC(boolean throwException) {64this.throwException = throwException;65}6667@Override68public void addNotificationListener(69String connectionId,70ObjectName name,71Subject subject)72throws SecurityException {73echo("addNotificationListener:");74echo("\tconnectionId: " + connectionId);75echo("\tname: " + name);76echo("\tsubject: " +77(subject == null ? null : subject.getPrincipals()));78if (throwException)79if (name.getCanonicalName().equals("domain:name=1,type=NB")80&&81subject != null82&&83subject.getPrincipals().contains(new JMXPrincipal("role")))84throw new SecurityException();85}8687@Override88public void removeNotificationListener(89String connectionId,90ObjectName name,91Subject subject)92throws SecurityException {93echo("removeNotificationListener:");94echo("\tconnectionId: " + connectionId);95echo("\tname: " + name);96echo("\tsubject: " +97(subject == null ? null : subject.getPrincipals()));98if (throwException)99if (name.getCanonicalName().equals("domain:name=2,type=NB")100&&101subject != null102&&103subject.getPrincipals().contains(new JMXPrincipal("role")))104throw new SecurityException();105}106107@Override108public void fetchNotification(109String connectionId,110ObjectName name,111Notification notification,112Subject subject)113throws SecurityException {114echo("fetchNotification:");115echo("\tconnectionId: " + connectionId);116echo("\tname: " + name);117echo("\tnotification: " + notification);118echo("\tsubject: " +119(subject == null ? null : subject.getPrincipals()));120if (!throwException)121if (name.getCanonicalName().equals("domain:name=2,type=NB")122&&123subject != null124&&125subject.getPrincipals().contains(new JMXPrincipal("role")))126throw new SecurityException();127}128}129130public class CustomJMXAuthenticator implements JMXAuthenticator {131@Override132public Subject authenticate(Object credentials) {133String role = ((String[]) credentials)[0];134echo("\nCreate principal with name = " + role);135return new Subject(true,136Collections.singleton(new JMXPrincipal(role)),137Collections.EMPTY_SET,138Collections.EMPTY_SET);139}140}141142public interface NBMBean {143public void emitNotification(int seqnum, ObjectName name);144}145146public static class NB147extends NotificationBroadcasterSupport148implements NBMBean {149@Override150public void emitNotification(int seqnum, ObjectName name) {151if (name == null) {152sendNotification(new Notification("nb", this, seqnum));153} else {154sendNotification(new Notification("nb", name, seqnum));155}156}157}158159public class Listener implements NotificationListener {160public final List<Notification> notifs = new CopyOnWriteArrayList<>();161162private final Semaphore s;163public Listener(Semaphore s) {164this.s = s;165}166@Override167public void handleNotification(Notification n, Object h) {168echo("handleNotification:");169echo("\tNotification = " + n);170echo("\tNotification.SeqNum = " + n.getSequenceNumber());171echo("\tHandback = " + h);172notifs.add(n);173s.release();174}175}176177/**178* Check received notifications179*/180public int checkNotifs(int size,181List<Notification> received,182List<ObjectName> expected) {183if (received.size() != size) {184echo("Error: expecting " + size + " notifications, got " +185received.size());186return 1;187} else {188for (Notification n : received) {189echo("Received notification: " + n);190if (!n.getType().equals("nb")) {191echo("Notification type must be \"nb\"");192return 1;193}194ObjectName o = (ObjectName) n.getSource();195int index = (int) n.getSequenceNumber();196ObjectName nb = expected.get(index);197if (!o.equals(nb)) {198echo("Notification source must be " + nb);199return 1;200}201}202}203return 0;204}205206/**207* Run test208*/209public int runTest(boolean enableChecks, boolean throwException)210throws Exception {211212echo("\n=-=-= " + (enableChecks ? "Enable" : "Disable") +213" notification access control checks " +214(!enableChecks ? "" : (throwException ? ": add/remove " :215": fetch ")) + "=-=-=");216217JMXConnectorServer server = null;218JMXConnector client = null;219220/*221* (!enableChecks)222* - List must contain three notifs from sources nb1, nb2 and nb3223* (enableChecks && !throwException)224* - List must contain one notif from source nb1225* (enableChecks && throwException)226* - List must contain two notifs from sources nb2 and nb3227*/228final int expected_notifs =229(!enableChecks ? 3 : (throwException ? 2 : 1));230231// Create a new MBeanServer232//233final MBeanServer mbs = MBeanServerFactory.createMBeanServer();234235try {236// Create server environment map237//238final Map<String,Object> env = new HashMap<>();239env.put("jmx.remote.authenticator", new CustomJMXAuthenticator());240if (enableChecks) {241env.put("com.sun.jmx.remote.notification.access.controller",242new NAC(throwException));243}244245// Create the JMXServiceURL246//247final JMXServiceURL url = new JMXServiceURL("service:jmx:rmi://");248249// Create a JMXConnectorServer250//251server = JMXConnectorServerFactory.newJMXConnectorServer(url,252env,253mbs);254255// Start the JMXConnectorServer256//257server.start();258259// Create server environment map260//261final Map<String,Object> cenv = new HashMap<>();262String[] credentials = new String[] { "role" , "password" };263cenv.put("jmx.remote.credentials", credentials);264265// Create JMXConnector and connect to JMXConnectorServer266//267client = JMXConnectorFactory.connect(server.getAddress(), cenv);268269// Get non-secure MBeanServerConnection270//271final MBeanServerConnection mbsc =272client.getMBeanServerConnection();273274// Create NB MBean275//276ObjectName nb1 = ObjectName.getInstance("domain:type=NB,name=1");277ObjectName nb2 = ObjectName.getInstance("domain:type=NB,name=2");278ObjectName nb3 = ObjectName.getInstance("domain:type=NB,name=3");279mbsc.createMBean(NB.class.getName(), nb1);280mbsc.createMBean(NB.class.getName(), nb2);281mbsc.createMBean(NB.class.getName(), nb3);282283// Add notification listener284//285Semaphore s = new Semaphore(0);286287Listener li = new Listener(s);288try {289mbsc.addNotificationListener(nb1, li, null, null);290if (enableChecks && throwException) {291echo("Didn't get expected exception");292return 1;293}294} catch (SecurityException e) {295if (enableChecks && throwException) {296echo("Got expected exception: " + e);297} else {298echo("Got unexpected exception: " + e);299return 1;300}301}302mbsc.addNotificationListener(nb2, li, null, null);303304System.out.println("\n+++ Expecting to receive " + expected_notifs +305" notification" + (expected_notifs > 1 ? "s" : "") +306" +++");307// Invoke the "sendNotification" method308//309mbsc.invoke(nb1, "emitNotification",310new Object[] {0, null},311new String[] {"int", "javax.management.ObjectName"});312mbsc.invoke(nb2, "emitNotification",313new Object[] {1, null},314new String[] {"int", "javax.management.ObjectName"});315mbsc.invoke(nb2, "emitNotification",316new Object[] {2, nb3},317new String[] {"int", "javax.management.ObjectName"});318319// Wait for notifications to be emitted320//321s.acquire(expected_notifs);322323// Remove notification listener324//325if (!throwException)326mbsc.removeNotificationListener(nb1, li);327try {328mbsc.removeNotificationListener(nb2, li);329if (enableChecks && throwException) {330echo("Didn't get expected exception");331return 1;332}333} catch (SecurityException e) {334if (enableChecks && throwException) {335echo("Got expected exception: " + e);336} else {337echo("Got unexpected exception: " + e);338return 1;339}340}341342int result = 0;343List<ObjectName> sources = new ArrayList();344sources.add(nb1);345sources.add(nb2);346sources.add(nb3);347result = checkNotifs(expected_notifs, li.notifs, sources);348if (result > 0) {349return result;350}351} catch (Exception e) {352echo("Failed to perform operation: " + e);353e.printStackTrace();354return 1;355} finally {356// Close the connection357//358if (client != null)359client.close();360361// Stop the connector server362//363if (server != null)364server.stop();365366// Release the MBeanServer367//368if (mbs != null)369MBeanServerFactory.releaseMBeanServer(mbs);370}371372return 0;373}374375/*376* Print message377*/378private static void echo(String message) {379System.out.println(message);380}381382public static void main(String[] args) throws Exception {383384System.out.println("\nTest notification access control.");385386NotificationAccessControllerTest nact =387new NotificationAccessControllerTest();388389int error = 0;390391error += nact.runTest(false, false);392393error += nact.runTest(true, false);394395error += nact.runTest(true, true);396397if (error > 0) {398final String msg = "\nTest FAILED! Got " + error + " error(s)";399System.out.println(msg);400throw new IllegalArgumentException(msg);401} else {402System.out.println("\nTest PASSED!");403}404}405}406407408