4 Replies Latest reply on May 23, 2007 2:02 AM by Lord Wilmore

    Accessing singleton MBean from a cluster node

    Lord Wilmore Newbie

      Hello!

      I have a cluster with 2 nodes (JBoss 4.0.5 GA) and a singleton MBean with name "kapart.mbean:service=ScheduleManager". The singleton works correctly, if the master fails it is started on the new master. The problem is, that I'd like to access this mbean from a session bean, which can run on any node. I tried the example described here:
      http://wiki.jboss.org/wiki/Wiki.jsp?page=JBossHASingletonRemoteAccess

      So i created a "singleton-jmx-adapter-service.xml" with code:

      <?xml version="1.0" encoding="UTF-8"?>
      <server>
       <mbean code="org.jboss.invocation.jrmp.server.JRMPProxyFactory" name="jboss.jmx:type=singletonadaptor,name=Invoker,protocol=jrmp,service=proxyFactory">
       <depends optional-attribute-name="InvokerName">jboss:service=invoker,type=jrmp</depends>
       <depends optional-attribute-name="TargetName">jboss.jmx:type=adaptor,name=Invoker</depends>
       <attribute name="JndiName">jmx/invoker/SingletonRMIAdaptor</attribute>
       <attribute name="ExportedInterfaces">org.jboss.jmx.adaptor.rmi.RMIAdaptor,org.jboss.jmx.adaptor.rmi.RMIAdaptorExt</attribute>
       <attribute name="ClientInterceptors">
       <interceptors>
       <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor>
       <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
       <interceptor>org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor</interceptor>
       <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor>
       </interceptors>
       </attribute>
       </mbean>
      </server>
      


      I put this document in the "deploy-hasingleton" directory on both servers. I tried to access the MBean like this:

       Hashtable jndiProperties = new Hashtable();
       jndiProperties.put( Context.INITIAL_CONTEXT_FACTORY, "org.jnp.interfaces.NamingContextFactory" );
       jndiProperties.put( Context.PROVIDER_URL, "localhost:1100" );
       jndiProperties.put( "java.naming.factory.url.pkgs","org.jboss.naming:org.jnp.interfaces" );
       Context context = new InitialContext( jndiProperties );
       RMIAdaptor rmiAdaptor = (RMIAdaptor) context.lookup("jmx/invoker/SingletonRMIAdaptor");
       if( (rmiAdaptor != null) && (rmiAdaptor.isRegistered(new ObjectName("kapart.mbean:service=ScheduleManager"))) ) {
       rmiAdaptor.invoke( new ObjectName("kapart.mbean:service=ScheduleManager"), "startSingleton", null, null );
       }
      


      1100 is my HAJNDI port.

      I got the following error:
      java.lang.SecurityException: Failed to authenticate principal=null, securityDomain=jmx-console
       at org.jboss.jmx.connector.invoker.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:97)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:88)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.invocation.jrmp.server.JRMPProxyFactory.invoke(JRMPProxyFactory.java:179)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.mx.interceptor.ReflectedDispatcher.invoke(ReflectedDispatcher.java:155)
       at org.jboss.mx.server.Invocation.dispatch(Invocation.java:94)
       at org.jboss.mx.server.Invocation.invoke(Invocation.java:86)
       at org.jboss.mx.server.AbstractMBeanInvoker.invoke(AbstractMBeanInvoker.java:264)
       at org.jboss.mx.server.MBeanServerImpl.invoke(MBeanServerImpl.java:659)
       at org.jboss.invocation.jrmp.server.JRMPInvoker$MBeanServerAction.invoke(JRMPInvoker.java:819)
       at org.jboss.invocation.jrmp.server.JRMPInvoker.invoke(JRMPInvoker.java:420)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:294)
       at sun.rmi.transport.Transport$1.run(Transport.java:153)
       at java.security.AccessController.doPrivileged(Native Method)
       at sun.rmi.transport.Transport.serviceCall(Transport.java:149)
       at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:466)
       at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:707)
       at java.lang.Thread.run(Thread.java:595)
       at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:247)
       at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:223)
       at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:126)
       at org.jboss.invocation.jrmp.server.JRMPInvoker_Stub.invoke(Unknown Source)
       at org.jboss.invocation.jrmp.interfaces.JRMPInvokerProxy.invoke(JRMPInvokerProxy.java:133)
       at org.jboss.invocation.InvokerInterceptor.invokeInvoker(InvokerInterceptor.java:365)
       at org.jboss.invocation.InvokerInterceptor.invoke(InvokerInterceptor.java:197)
       at org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor.invoke(InvokerAdaptorClientInterceptor.java:66)
       at org.jboss.proxy.SecurityInterceptor.invoke(SecurityInterceptor.java:70)
       at org.jboss.proxy.ClientMethodInterceptor.invoke(ClientMethodInterceptor.java:74)
       at org.jboss.proxy.ClientContainer.invoke(ClientContainer.java:100)
       at $Proxy100.isRegistered(Unknown Source)
       at com.astron.kapart.schedule.ScheduleManagerBean.clearAll(ScheduleManagerBean.java:59)
       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
       at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
       at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
       at java.lang.reflect.Method.invoke(Method.java:585)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
       at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
       at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerInterceptor.java:54)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:46)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:79)
       at org.jboss.aspects.tx.TxInterceptor$Required.invoke(TxInterceptor.java:191)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.aspects.tx.TxPropagationInterceptor.invoke(TxPropagationInterceptor.java:76)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.stateless.StatelessInstanceInterceptor.invoke(StatelessInstanceInterceptor.java:62)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.aspects.remoting.ReplicantsManagerInterceptor.invoke(ReplicantsManagerInterceptor.java:51)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.aspects.security.AuthenticationInterceptor.invoke(AuthenticationInterceptor.java:77)
       at org.jboss.ejb3.security.Ejb3AuthenticationInterceptor.invoke(Ejb3AuthenticationInterceptor.java:102)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.ENCPropagationInterceptor.invoke(ENCPropagationInterceptor.java:47)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.asynchronous.AsynchronousInterceptor.invoke(AsynchronousInterceptor.java:106)
       at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
       at org.jboss.ejb3.stateless.StatelessContainer.dynamicInvoke(StatelessContainer.java:263)
       at org.jboss.aop.Dispatcher.invoke(Dispatcher.java:106)
       at org.jboss.aspects.remoting.AOPRemotingInvocationHandler.invoke(AOPRemotingInvocationHandler.java:82)
       at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:828)
       at org.jboss.remoting.ServerInvoker.invoke(ServerInvoker.java:681)
       at org.jboss.remoting.transport.socket.ServerThread.processInvocation(ServerThread.java:358)
       at org.jboss.remoting.transport.socket.ServerThread.dorun(ServerThread.java:412)
       at org.jboss.remoting.transport.socket.ServerThread.run(ServerThread.java:239)
      


      I have a user/pass account to my jmx-console, but I don't know if it counts.

      Thanx in advance.

        • 1. Re: Accessing singleton MBean from a cluster node
          Brian Stansberry Master

          Looks like the jboss.jmx:type=adaptor,name=Invoker service is secured, using the same security domain as the JMX console. So, you need to associate a principal and credential that the jmx-console domain will accept with the caller thread before invoking on the adaptor.

          This can be done as follows:

          ... your existing stuff
          String user = "foo"; // replace with whatever you want
          org.jboss.security.SimplePrincipal prin = new SimplePrincipal(user);
          org.jboss.security.SecurityAssociation.setPrincipal(prin);
          
          char[] pwd = "bar".toCharArray(); // replace with whatever you want
          org.jboss.security.SecurityAssociation.setCredential(pwd);
          if( (rmiAdaptor != null) && (rmiAdaptor.isRegistered(new ObjectName("kapart.mbean:service=ScheduleManager"))) ) {
           rmiAdaptor.invoke( new ObjectName("kapart.mbean:service=ScheduleManager"), "startSingleton", null, null );
           }
          


          Probably a better idea is to call SecurityAssociation.getPrincipal() and getCredential() first and cache the results in a local variable. Then do the above in a try/finally block. In the finally, reset the principal and credential to whatever they were. This way if the thread has a end user's principal and credential associated with it, they won't be lost.


          • 2. Re: Accessing singleton MBean from a cluster node
            Lord Wilmore Newbie

            Thank you! This one works correctly! In the meantime I tried out the folloowing for the singleton-jmx-adaptor-service.xml:

             <mbean code="org.jboss.invocation.jrmp.server.JRMPProxyFactory" name="jboss.jmx:type=adaptor,name=SingletonInvoker,protocol=jrmp,service=proxyFactory">
             <depends optional-attribute-name="InvokerName">jboss:service=invoker,type=jrmp</depends>
             <depends optional-attribute-name="TargetName">jboss.jmx:type=adaptor,name=SingletonInvoker</depends>
             <attribute name="JndiName">jmx/invoker/SingletonRMIAdaptor</attribute>
             <attribute name="ExportedInterfaces">org.jboss.jmx.adaptor.rmi.RMIAdaptor,org.jboss.jmx.adaptor.rmi.RMIAdaptorExt</attribute>
             <attribute name="ClientInterceptors">
             <interceptors>
             <interceptor>org.jboss.proxy.ClientMethodInterceptor</interceptor>
             <interceptor>org.jboss.proxy.SecurityInterceptor</interceptor>
             <interceptor>org.jboss.jmx.connector.invoker.client.InvokerAdaptorClientInterceptor</interceptor>
             <interceptor>org.jboss.invocation.InvokerInterceptor</interceptor>
             </interceptors>
             </attribute>
             </mbean>
             <mbean code="org.jboss.jmx.connector.invoker.InvokerAdaptorService" name="jboss.jmx:type=adaptor,name=SingletonInvoker" xmbean-dd="">
             <xmbean>
             <description>The JMX Detached Invoker Service</description>
             <class>org.jboss.jmx.connector.invoker.InvokerAdaptorService</class>
             <attribute access="read-only" getMethod="getName">
             <description>The class name of the MBean</description>
             <name>Name</name>
             <type>java.lang.String</type>
             </attribute>
             <attribute access="read-only" getMethod="getState">
             <description>The status of the MBean</description>
             <name>State</name>
             <type>int</type>
             </attribute>
             <attribute access="read-only" getMethod="getStateString">
             <description>The status of the MBean in text form</description>
             <name>StateString</name>
             <type>java.lang.String</type>
             </attribute>
             <attribute access="read-write" getMethod="getExportedInterfaces" setMethod="setExportedInterfaces">
             <description>The interfaces the invoker proxy supports</description>
             <name>ExportedInterfaces</name>
             <type>[Ljava.lang.Class;</type>
             </attribute>
             <attribute access="read-only" getMethod="getMethodMap">
             <description>Map(Long hash, Method) of the proxy interface methods</description>
             <name>MethodMap</name>
             <type>java.util.Map</type>
             </attribute>
             <operation>
             <description>The start lifecycle operation</description>
             <name>start</name>
             </operation>
             <operation>
             <description>The stop lifecycle operation</description>
             <name>stop</name>
             </operation>
             <operation>
             <description>The detyped lifecycle operation (for internal use only)</description>
             <name>jbossInternalLifecycle</name>
             <parameter>
             <description>The lifecycle operation</description>
             <name>method</name>
             <type>java.lang.String</type>
             </parameter>
             <return-type>void</return-type>
             </operation>
             <operation>
             <description>The detached invoker entry point</description>
             <name>invoke</name>
             <parameter>
             <description>The method invocation context</description>
             <name>invocation</name>
             <type>org.jboss.invocation.Invocation</type>
             </parameter>
             <return-type>java.lang.Object</return-type>
             </operation>
             </xmbean>
             <attribute name="ExportedInterfaces">org.jboss.jmx.adaptor.rmi.RMIAdaptor,org.jboss.jmx.adaptor.rmi.RMIAdaptorExt</attribute>
             </mbean>
             <mbean code="org.jboss.ha.singleton.HASingletonController" name="jboss.hasingleton:service=RMIAdaptorSingletonController">
             <depends>jboss:service=DefaultPartition</depends>
             <depends>jboss.jmx:type=adaptor,name=SingletonInvoker</depends>
             <attribute name="TargetName">jboss.jmx:type=adaptor,name=SingletonInvoker</attribute>
             <attribute name="TargetStartMethod">start</attribute>
             <attribute name="TargetStopMethod">stop</attribute>
             </mbean>
            


            This one worked too without setting the security principal and credential, and I don't really understand, why? This declaration removes the mbean from the security domain?

            • 3. Re: Accessing singleton MBean from a cluster node
              Brian Stansberry Master

              Yes, that declaration does not include your mbean in a security domain. Have a look at your deploy/jmx-invoker-service.xml file, jboss.jmx:type=adaptor,name=Invoker mbean, section about the invoke operation. You must have this uncommented:

              <descriptors>
               <interceptors>
               <interceptor code="org.jboss.jmx.connector.invoker.AuthenticationInterceptor"
               securityDomain="java:/jaas/jmx-console"/>
               </interceptors>
              </descriptors>


              That adds server side security to the RMIAdaptor. Your singleton-jmx-adaptor-service.xml doesn't include that, so the service is unsecured.

              In 4.0.5, the section above was commented out by default. The fact that you have it uncommented may indicate that someone in your organization wants that service secured (not a bad idea!!). So, you might want to double check before deploying a second, unsecured, version.

              • 4. Re: Accessing singleton MBean from a cluster node
                Lord Wilmore Newbie

                Yes, that code part is uncommented in my config and I prefer this secured version of course, but I think it was uncommented by defalut. (I used the installer version of 4.0.5 with 'ejb3-clustered' settings)

                Anyway, thanks for the help!