Announcement Announcement Module
Collapse
No announcement yet.
How to secure jmxServer (JConsole) Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • How to secure jmxServer (JConsole)

    I have been trying to secure the JConsole access to my stand-alone Java Server which uses Spring 2.5, but it seems anyone that knows the URL and jmx port can access JConsole without being challenged for login credentials. The Sun docs say that by default authentication is enabled, but it seems not.

    http://java.sun.com/j2se/1.5.0/docs/...tml#connecting

    Anyway, I have been trying to secure it via spring-jmx-config.xml, since providing JVM parms when launching the server has no effect. Am I on the right track or can somebody tell me what I am doing wrong? The doc says if you give it a non-existent password location you will not have access, but JConsole continues to be wide open...

    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans-2.0.dtd">
    <beans>
    <bean class="org.springframework.remoting.rmi.RmiRegistr yFactoryBean">
    <property name="port" value="17999"/>
    </bean>

    <bean id="jmxServer" class="org.springframework.jmx.support.ConnectorSe rverFactoryBean">
    <property name="serviceUrl" value="service:jmx:rmi://localhost/jndi/rmi://localhost:17999/Pipeline"/>
    <property name="registrationBehaviorName" value="REGISTRATION_REPLACE_EXISTING"/>
    <property name="environmentMap">
    <map>
    <entry key="com.sun.management.jmxremote.authenticate" value-ref="true"/>
    <entry key="com.sun.management.jmxremote.password.file" value-ref="foo"/>
    </map>
    </property>

    </bean>

    <bean id="mbeanExporter" class="org.springframework.jmx.export.MBeanExporte r">
    ....
    </bean>

    </beans>

    Thanks in advance to anyone who can point me in the right direction.

  • #2
    JMXAuthenticator

    i had the same issue and i've found out by implementing JMXAuthenticator the most flexible way to secure jconsole and authenticate via spring security :

    config :

    Code:
    <util:constant id="jmx.auth.attribute" static-field="javax.management.remote.JMXConnectorServer.AUTHENTICATOR"/>
    
    <bean id="jmx.authenticator" class="wims.cycle.jmx.JmxSecurityAuthenticator"/>
    
    <util:map id="jmx.environment">
    		<entry key-ref="jmx.auth.attribute" value-ref="jmx.authenticator"/>
    	</util:map>
    
    <bean id="jmx.server" class="org.springframework.jmx.support.MBeanServerFactoryBean"
    		p:locateExistingServerIfPossible="false"/>
    
    <bean id="jmx.server.connector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="jmx.registry"
    		p:server-ref="jmx.server"
    		p:objectName="connector:name=rmi"
    		p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/cycle"
    		p:environmentMap-ref="jmx.environment"
    />
    JMXAuthenticator :

    Code:
    public class JmxSecurityAuthenticator implements JMXAuthenticator{
    
    	@Resource
    	private AuthenticationManager authMgr;
    
    	public Subject authenticate(Object credentials) {
    		try{
    			String[] info = (String[]) credentials;
    			
    			Authentication auth = authMgr.authenticate(new UsernamePasswordAuthenticationToken(info[0],info[1]));
    			
    			
    			Subject s = new Subject();
    			s.getPrincipals().add(new JMXPrincipal(auth.getName()));
    			return s;
    		}catch(Exception e){
    			throw new SecurityException(e);
    		}
    	}
    
    }

    Comment


    • #3
      ConnectorServerFactoryBean environment map properties

      I tried the JMXAuthenticator approach which was posted, but it seems the poster is using a version of Spring different than 2.5? I am getting errors on the environment map properties for ConnectorServerFactoryBean. Does anyone know where these properties are documented? I am not seeing them documented anywhere...

      Comment


      • #4
        which errors ?

        i've used JMXAuthenticator against
        spring pre-2.5 era , spring 2.5 till 2.5.6 and post-2.5 (current 3.0.0.M3)

        Comment


        • #5
          Doc says :
          The secure JMX server will be running on port 9998.
          so should this be
          service:jmx:rmi:///jndi/rmi://localhost:9998/JMXSecureConnector ?
          or is the connector opened at port 1099 ?

          Comment


          • #6
            Here is some info on my experience with getting the authentication part to work...

            In case any one else was confused about what "p:" namespace prefix refers to here is a useful ref:

            http://blog.springsource.com/2006/11...-in-spring-20/

            You will need to declare both the "util:" and "p:" namespace in the bean config file. Here is what eventually worked for me after much trial and error...

            Code:
            <beans xmlns="http://www.springframework.org/schema/beans"
                   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
                   xmlns:security="http://www.springframework.org/schema/security"
                   xmlns:util="http://www.springframework.org/schema/util"
                   xmlns:p="http://www.springframework.org/schema/p"
                   xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schem...-beans-2.0.xsd
                                       http://www.springframework.org/schema/security http://www.springframework.org/schem...curity-2.0.xsd
                   http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
                
            
                <!-- JXM Authentication -->
                <util:constant id="jmx.auth.attribute" static-field="javax.management.remote.JMXConnectorServer.AUTHENTICATOR"/>
            
                <bean id="jmx.authenticator" class="my.impl.package.JMXAuthenticatorImpl">
                    <property name="authManager" ref="_authenticationManager"/>
                </bean>
            
                <util:map id="jmx.environment">
                    <entry key-ref="jmx.auth.attribute" value-ref="jmx.authenticator"/>
                </util:map>
            
                <bean id="jmx.server" class="org.springframework.jmx.support.MBeanServerFactoryBean"
                                p:locateExistingServerIfPossible="true"/>
            
                <bean id="jmx.server.connector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="jmx.registry"
                                p:server-ref="jmx.server"
                                p:objectName="connector:name=rmi"
                                p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/jmxRMIConnector"
                                p:environmentMap-ref="jmx.environment"
                />
            
                <!-- Needed to declare the following -->
                <bean id="jmx.registry" class="org.springframework.remoting.rmi.RmiRegistryFactoryBean">
                    <property name="port" value="1099"/>
                </bean>
            
            </beans>
            Last edited by farrukh_najmi; Feb 28th, 2011, 02:45 PM.

            Comment


            • #7
              How to do authorization for an authenticated JMX operation?

              I was able to get JMX Authentication working with spring-security using spring-core 3.0.5.RELEASE (see previous message). However, I am still working to figure out how I can get the Authentication object when a @ManagedAttribute is set via a JMX Client like jvisualvm. I need this to determine authorization and access control. Does any one have any suggestions on how I can get the Authentication object when my @ManagedAttribute setter is called from an authenticated JMX client?

              Comment


              • #8
                I have gotten Authorization to work as follows...
                • Use SecurityContextHolder.getContext().setAuthenticati on(auth); in the JMXAuthenticatorImpl.authenticate method
                • In JMX ManagedOperations that require authorization use SecurityContextHolder.getContext().getAuthenticati on(); to get the AUthentication object and then use it for authorization

                I found that sometimes the SecurityContextHolder.getContext().getAuthenticati on(); returns null initially (perhaps because server was still booting). Once server was in steady state it seemed to work fine and return an Authentication object.

                Comment


                • #9
                  Originally posted by farrukh_najmi View Post
                  I found that sometimes the SecurityContextHolder.getContext().getAuthenticati on(); returns null initially (perhaps because server was still booting). Once server was in steady state it seemed to work fine and return an Authentication object.
                  Actually I am seeing the SecurityContextHolder.getContext().getAuthenticati on(); return null more often than not. This leads me to believe that the JMX authentication thread (where SecurityContextHolder.getContext().setAuthenticati on(); is called) and the JMX operation thread (where SecurityContextHolder.getContext().getAuthenticati on(); is called) are not the same typically.

                  What I learned is that one MUST NOT save the authenticated JMX Connection within jvisualvm or else the authentication happens automatically when you start jvisualvm and it is in a separate thread than the subsequent JMX secure operation. As long as you create a new authenticated JMX Connection each time you start jvisualvm then the authentication happens in same thread as subsequent JMX operation. It is obviously very brittle to use ThreadLocal mechanism such as SecurityContextHolder.getContext().authentication.

                  Is there a better way?
                  Last edited by farrukh_najmi; Mar 3rd, 2011, 10:25 AM.

                  Comment


                  • #10
                    authorization

                    store authentication :

                    Code:
                    public Subject authenticate(Object credentials) {
                    		try{
                    			Authentication authentication = authMgr.authenticate(getAuthentication(credentials));
                    			registry.register(authentication.getName(), authentication);
                    			return getSubject(authentication);
                    		}catch(AuthenticationException e){
                    			logger.warn(e);
                    			throw new SecurityException(e);
                    		}
                    	}
                    set a delegatingmbean or use aop :

                    Code:
                    <aop:config>
                     			<aop:pointcut id="jmx-pointcut" expression="execution(public * javax.management.MBeanServer.invoke(..))" />
                     			<aop:aspect ref="jmx-security-handler">
                     				<aop:around  pointcut-ref="jmx-pointcut" method="invoke"/>
                     			</aop:aspect>
                     		</aop:config>
                    lookup authentication info :

                    Code:
                    public Object invoke(ProceedingJoinPoint pjp) throws Throwable{
                    		try{
                    			SecurityContextHolder.getContext().setAuthentication(lookup());
                    			return pjp.proceed();
                    		}finally{
                    			SecurityContextHolder.clearContext();
                    			if (logger.isDebugEnabled()) {
                                    logger.debug("Cleared SecurityContextHolder.");
                                }
                    		}
                    	}
                    
                    private Authentication lookup(){
                    		try{
                             	return registry.get(lookup(Subject.getSubject(AccessController.getContext())));
                    		}catch(Exception e){
                    			logger.warn(e.getMessage());
                    		}
                    		return null;
                    	}
                    	
                    	private String lookup(Subject subject){
                    		return subject.getPrincipals(JMXPrincipal.class).iterator().next().getName();
                    	}
                    Last edited by wims.tijd; Mar 4th, 2011, 06:51 AM.

                    Comment


                    • #11
                      Many thanks for the detailed response! What is the type for the variable registry?

                      Comment


                      • #12
                        could not find a spring suitable class so:

                        Code:
                        public interface AuthenticationRegistry {
                        	
                        	Authentication register(String key, Authentication authentication);
                        	Authentication remove(String key);
                        
                        }
                        and :

                        Code:
                        private Map<String,Authentication> registry = Collections.synchronizedMap(new HashMap<String,Authentication>());
                        
                        public Authentication register(String key, Authentication authentication) {
                        		if(key == null){
                        			key = authentication.getName();
                        		}
                        		return registry.put(key, authentication);
                        	}
                        
                        	public Authentication remove(String key) {
                        		return registry.remove(key);
                        	}

                        Comment


                        • #13
                          Confirming that the solution posted by wims.tijd involving spring-aop worked like a charm! Thank you wims.tijd you are a lifesaver.

                          Comment


                          • #14
                            Hi,

                            I am, trying to implement authentication for JMX accsess via Jconsole using JMXMP protocol.
                            I followed exactly the procedure and implemented a custom JMXAuthenticatorImpl.
                            My application did call the custom authenticator, but the argument 'credentials has only the URL.
                            They do not contain the username and password that was entered on the JConsole GUI.
                            What am I missing?

                            thanks
                            Srini

                            Originally posted by wims.tijd View Post
                            i had the same issue and i've found out by implementing JMXAuthenticator the most flexible way to secure jconsole and authenticate via spring security :

                            config :

                            Code:
                            <util:constant id="jmx.auth.attribute" static-field="javax.management.remote.JMXConnectorServer.AUTHENTICATOR"/>
                            
                            <bean id="jmx.authenticator" class="wims.cycle.jmx.JmxSecurityAuthenticator"/>
                            
                            <util:map id="jmx.environment">
                            		<entry key-ref="jmx.auth.attribute" value-ref="jmx.authenticator"/>
                            	</util:map>
                            
                            <bean id="jmx.server" class="org.springframework.jmx.support.MBeanServerFactoryBean"
                            		p:locateExistingServerIfPossible="false"/>
                            
                            <bean id="jmx.server.connector" class="org.springframework.jmx.support.ConnectorServerFactoryBean" depends-on="jmx.registry"
                            		p:server-ref="jmx.server"
                            		p:objectName="connector:name=rmi"
                            		p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/cycle"
                            		p:environmentMap-ref="jmx.environment"
                            />
                            JMXAuthenticator :

                            Code:
                            public class JmxSecurityAuthenticator implements JMXAuthenticator{
                            
                            	@Resource
                            	private AuthenticationManager authMgr;
                            
                            	public Subject authenticate(Object credentials) {
                            		try{
                            			String[] info = (String[]) credentials;
                            			
                            			Authentication auth = authMgr.authenticate(new UsernamePasswordAuthenticationToken(info[0],info[1]));
                            			
                            			
                            			Subject s = new Subject();
                            			s.getPrincipals().add(new JMXPrincipal(auth.getName()));
                            			return s;
                            		}catch(Exception e){
                            			throw new SecurityException(e);
                            		}
                            	}
                            
                            }

                            Comment


                            • #15
                              Originally posted by farrukh_najmi View Post
                              Confirming that the solution posted by wims.tijd involving spring-aop worked like a charm! Thank you wims.tijd you are a lifesaver.

                              Hi Farrukh najim

                              Thanks for the reply.

                              The solution posted is using RMI protocol (JMX RMI).

                              p:serviceUrl="service:jmx:rmi://localhost/jndi/rmi://localhost:1099/cycle"

                              But I am trying to use JMXMP protocol.

                              service:jmx:jmxmp://localhost:9998

                              When I followed the procedure suggested by wims.tijd by chaning protocol url, I am seeing some issues.
                              First, I do see that my custom JMXAuthenticatorImpl is geting called. But the credential object it is geting does not
                              contain user name or password. It contains only one element in the array, that is the URL.

                              Application started.
                              May 26, 2011 12:47:43 PM SocketConnectionServer accept
                              FINER: Waiting a new connection...
                              May 26, 2011 12:47:51 PM SocketConnection Constructor
                              FINER: Creating with a socket Socket[addr=/10.40.141.40,port=2412,localport=9998]
                              May 26, 2011 12:47:51 PM GenericConnectorServer Receiver.run
                              FINER: received connection request.
                              May 26, 2011 12:47:51 PM GenericConnectorServer Receiver.run
                              FINER: waiting for connection.
                              May 26, 2011 12:47:51 PM SynchroMessageConnectionServerImpl accept
                              FINER: Waiting a coming client...
                              May 26, 2011 12:47:51 PM SocketConnectionServer accept
                              FINER: Waiting a new connection...
                              May 26, 2011 12:47:51 PM SocketConnection connect
                              FINER: First time to connect to the server.
                              May 26, 2011 12:47:51 PM AdminServer connectionOpen
                              FINER: >>>>> Handshake Begin <<<<<
                              May 26, 2011 12:47:51 PM AdminServer connectionOpen
                              FINER: Server Supported Profiles [ null ]
                              May 26, 2011 12:47:51 PM AdminServer connectionOpen
                              FINER: Server JMXMP Version [ 1.0 ]
                              May 26, 2011 12:47:51 PM SocketConnection writeMessage
                              FINEST: Write a message ...
                              May 26, 2011 12:47:51 PM SocketConnection readMessage
                              FINEST: Read a message ...
                              May 26, 2011 12:47:51 PM AdminServer connectionOpen
                              FINER: >>>>> Handshake End <<<<<
                              May 26, 2011 12:47:51 PM AdminServer connectionOpen
                              FINER: Client Context Object [ [Ljava.lang.String;@109ea96 ]
                              *******Inside JMXAuthenticatorImpl******************

                              CLass Of credential obj=[Ljava.lang.Object;
                              Elements in the cred array=2
                              CLass Of credential obj=java.lang.String
                              name=jmxmp://lchi069094.prod.ad.merc.chicago.cme.com:2412 539419
                              password=null

                              When I looked at the source code of the implementation of com.sun.jmx.remote.opt.security.AdminServer that is calling my JMXAuthenticatorImpl
                              I see it is using something called connectionId to create credential object. AS anyone tried the authentication with JMXMP protocol?

                              thanks
                              Srini

                              Comment

                              Working...
                              X