/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.gemstone.gemfire.management.internal.security;

import com.gemstone.gemfire.internal.AvailablePort;
import com.gemstone.gemfire.management.ManagementException;
import com.gemstone.gemfire.management.internal.MBeanJMXAdapter;
import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;

import javax.management.DynamicMBean;
import javax.management.MBeanServer;
import javax.management.MBeanServerConnection;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectInstance;
import javax.management.ObjectName;
import javax.management.ReflectionException;
import java.io.IOException;
import java.util.Set;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.mock;

public class MBeanSecurityJUnitTest {

  private static int jmxManagerPort = AvailablePort.getRandomAvailablePort(AvailablePort.SOCKET);

  @ClassRule
  public static JsonAuthorizationMBeanServerStartRule serverRule = new JsonAuthorizationMBeanServerStartRule(jmxManagerPort, "cacheServer.json");

  @Rule
  public MBeanServerConnectionRule connectionRule = new MBeanServerConnectionRule(jmxManagerPort);


  /**
   * No user can call createBean or unregisterBean of any domain
   */
  @Test
  @JMXConnectionConfiguration(user = "superuser", password = "1234567")
  public void testNoAccessWithWhoever() throws Exception{
    MBeanServerConnection con = connectionRule.getMBeanServerConnection();
    assertThatThrownBy(
        () -> con.createMBean("FakeClassName", new ObjectName("GemFire", "name", "foo"))
    ).isInstanceOf(SecurityException.class);

    assertThatThrownBy(
        () -> con.unregisterMBean(new ObjectName("GemFire", "name", "foo"))
    ).isInstanceOf(SecurityException.class);

    // user is not allowed to create beans of other domains either
    assertThatThrownBy(
        () -> con.createMBean("FakeClassName", new ObjectName("OtherDomain", "name", "foo"))
    ).isInstanceOf(SecurityException.class);
  }

  /*
  * looks like everyone can query for beans, but the AccessControlMXBean is filtered from the result
  */
  @Test
  @JMXConnectionConfiguration(user = "stranger", password = "1234567")
  public void testQueryBean() throws MalformedObjectNameException, IOException {
    MBeanServerConnection con = connectionRule.getMBeanServerConnection();
    Set<ObjectInstance> objects = con.queryMBeans(ObjectName.getInstance(ResourceConstants.OBJECT_NAME_ACCESSCONTROL), null);
    assertThat(objects.size()).isEqualTo(0); // no AccessControlMBean in the query result

    objects = con.queryMBeans(ObjectName.getInstance("GemFire:service=CacheServer,*"), null);
    assertThat(objects.size()).isEqualTo(1);
  }

  /*
  * These calls does not go through the MBeanServerWrapper authentication, therefore is not throwing the SecurityExceptions
   */
  @Test
  public void testLocalCalls() throws Exception{
    MBeanServer server = MBeanJMXAdapter.mbeanServer;
    assertThatThrownBy(
        () -> server.createMBean("FakeClassName", new ObjectName("GemFire", "name", "foo"))
    ).isInstanceOf(ReflectionException.class);

    MBeanJMXAdapter adapter = new MBeanJMXAdapter();
    assertThatThrownBy(
        () -> adapter.registerMBean(mock(DynamicMBean.class), new ObjectName("MockDomain", "name", "mock"), false)
    ).isInstanceOf(ManagementException.class);

  }
}

@@ -1028,24 +1028,91 @@
 JMXAdapter;%0A
+import com.gemstone.gemfire.test.junit.categories.IntegrationTest;%0A
 import org.j
@@ -1172,16 +1172,67 @@
 it.Test;
+%0Aimport org.junit.experimental.categories.Category;
 %0A%0Aimport
@@ -1738,16 +1738,49 @@
 .mock;%0A%0A
+@Category(IntegrationTest.class)%0A
 public c

Add test category