Starting a JMX agent with a custom JAAS login module with which login () always returns true

I am creating a custom JAAS module for a JMX instance. The file that is being executed is the following:

MBean interface

package com.this.mbean;

public interface ImplementationMBean {

    public void setName(String name);
    public String getName();

    public void setNumber(int number);
    public int getNumber();
    public boolean getKilled();
    public void setKilled(boolean killed);
}

      

Implementation class

package com.test.mbean;

    public class Implementation implements ImplementationMBean {

        private String name ;
        private int number;
        private boolean killed = false;

        public Implementation(String name, int number) {
            this.name = name;
            this.number = number;
        }

        @Override
        public void setName(String name) {
            this.name = name;

        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public void setNumber(int number) {
            this.number = number;
        }

        @Override
        public int getNumber() {
            return number;
        }

        @Override
        public boolean getKilled() {
            return killed;
        }

        @Override
        public void setKilled(boolean killed) {
            this.killed = killed;

        }

    }

      

RunningImplementation Class

package com.test.running;

import java.lang.management.ManagementFactory;
import com.test.mbean.*;

import javax.management.InstanceAlreadyExistsException;
import javax.management.MBeanRegistrationException;
import javax.management.MBeanServer;
import javax.management.MalformedObjectNameException;
import javax.management.NotCompliantMBeanException;
import javax.management.ObjectName;

public class RunningImplementation {

    public static final String name = "defaultName";
    public static final int number = 100;

    public static void main(String[] args) 
            throws MalformedObjectNameException, InterruptedException, 
            InstanceAlreadyExistsException, MBeanRegistrationException, 
            NotCompliantMBeanException{

        //get MBean Server
        MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
        //register MBean
        ImplementationMBean mBean = new Implementation(name, number);
        ObjectName name = new ObjectName("com.bard.mbean:type=ConcreteImplementation");

        mbs.registerMBean(mBean, name);

        do{
            Thread.sleep(1000);
            System.out.println("Name = " + mBean.getName() + ", number = " + mBean.getNumber());
        }while(mBean.getKilled() == false);

    }
}

      

This is packaged in a JAR file named MBeanSecure.jar.

I have enabled jmx agent with

-Dcom.sun.management.jmxremote

      

I set it up to run on localhost on port 1234:

-Dcom.sun.management.jmxremote.port=1234

      

I configured the JMX agent to use the specified JAAS configuration entry:

-Dcom.sun.management.login.config=Sample

      

and specified the path to the Jaas config file:

-Djava.security.auth.login.config=sample_jaas.config

      

sample_jaas.config

Sample {
   sample.module.SampleLoginModule required debug=true;
   authIdentity=monitorRole;
};

      

monitor role is specified in jmxremote.access

-Dcom.sun.management.jmxremote.access.file=jmxremote.access

      

and looks like this:

monitorRole readonly
controleRole readwrite

      

my Loginmodule is simple in that it returns true.

SampleLoginModule

package sample.module;

import java.util.*;
import java.io.IOException;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.*;
import sample.principal.SamplePrincipal;

public class SampleLoginModule implements LoginModule {

    // initial state
    private Subject subject;
    private CallbackHandler callbackHandler;
    private Map sharedState;
    private Map options;

    // configurable option
    private boolean debug = false;

    // the authentication status
    private boolean succeeded = false;
    private boolean commitSucceeded = false;

    // username and password
    private String username;
    private char[] password;

    // testUser SamplePrincipal
    private SamplePrincipal userPrincipal;

    public void initialize(Subject subject, CallbackHandler callbackHandler,
            Map sharedState, Map options) {

        this.subject = subject;
        this.callbackHandler = callbackHandler;
        this.sharedState = sharedState;
        this.options = options;

        // initialize any configured options
        debug = "true".equalsIgnoreCase((String)options.get("debug"));
    }

    public boolean login() throws LoginException {
        return true;
    }

    public boolean commit() throws LoginException {
        if (succeeded == false) {
            return false;
        } else {
            // add a Principal (authenticated identity)
            // to the Subject

            // assume the user we authenticated is the SamplePrincipal
            userPrincipal = new SamplePrincipal(username);
            if (!subject.getPrincipals().contains(userPrincipal))
                subject.getPrincipals().add(userPrincipal);

            if (debug) {
                System.out.println("\t\t[SampleLoginModule] " +
                    "added SamplePrincipal to Subject");
            }

            // in any case, clean out state
            username = null;
            for (int i = 0; i < password.length; i++)
            password[i] = ' ';
            password = null;

            commitSucceeded = true;
            return true;
        }
    }

    public boolean abort() throws LoginException {
        if (succeeded == false) {
            return false;
        } else if (succeeded == true && commitSucceeded == false) {
            // login succeeded but overall authentication failed
            succeeded = false;
            username = null;
            if (password != null) {
                for (int i = 0; i < password.length; i++)
                    password[i] = ' ';
                password = null;
                }
            userPrincipal = null;
        } else {
            // overall authentication succeeded and commit succeeded,
            // but someone else commit failed
            logout();
        }
        return true;
    }

    public boolean logout() throws LoginException {

        subject.getPrincipals().remove(userPrincipal);
        succeeded = false;
        succeeded = commitSucceeded;
        username = null;
        if (password != null) {
            for (int i = 0; i < password.length; i++)
            password[i] = ' ';
            password = null;
        }
        userPrincipal = null;
        return true;
    }
}

      

with the main class:

SamplePrincipal

package sample.principal;

import java.security.Principal;

public class SamplePrincipal implements Principal, java.io.Serializable {

    private String name;


    public SamplePrincipal(String name) {
    if (name == null)
        throw new NullPointerException("illegal null input");

    this.name = name;
    }


    public String getName() {
    return name;
    }


    public String toString() {
    return("SamplePrincipal:  " + name);
    }


    public boolean equals(Object o) {
    if (o == null)
        return false;

        if (this == o)
            return true;

        if (!(o instanceof SamplePrincipal))
            return false;
        SamplePrincipal that = (SamplePrincipal)o;

    if (this.getName().equals(that.getName()))
        return true;
    return false;
    }


    public int hashCode() {
    return name.hashCode();
    }
}

      

When I run the code using:

java -Dcom.sun.management.jmxremote.port=1234 -Dcom.sun.management.jmxremote.login.config=Sample -Dcom.java.security.auth.login.config=sample_jaas.config -Djava.security.policy==sampleazn.policy -Dcom.sun.management.jmxremote.access.file=jmxremote.access -jar MBeanSecure.jar

      

Code is executed that regularly outputs

Name = defaultName, number = 100

      

Then I try to access the JMX agent through JConsole

jconsole

      

and this will open a Jconsole window showing the process.

However, when I try to connect to it as a remote process, I get a "Connection Error" error. This is difficult to debug as I don't see any logs where this is happening. Am I correct in thinking that using

com.sun.management.jmxremote.login.config

      

Am I overriding the default loginbehaviour username? In this case, it should check my Jaas config, run the login module, which always returns true, and allow the user under the control of the Role monitor?

I believe the error is in the config file, but it's hard to confirm settings or debugs given the scanty documentation.

+3


source to share


2 answers


Solved:

I could debug the problems by running:

jconsole -debug

      

which pointed out that my config file has a syntax error and is required:



Sample {
   sample.module.SampleLoginModule required debug=true
   authIdentity=monitorRole;
};

      

instead

Sample {
   sample.module.SampleLoginModule required debug=true;
   authIdentity=monitorRole;
};

      

notice one semicolon

+1


source


I would like to fix a bug in this code. Changing the login method only:

System.out.println("Login Module - login called");
    if (callbackHandler == null) {
        throw new LoginException("Oops, callbackHandler is null");
    }

    Callback[] callbacks = new Callback[2];
    callbacks[0] = new NameCallback("name:");
    callbacks[1] = new PasswordCallback("password:", false);

    try {
        callbackHandler.handle(callbacks);
    } catch (IOException e) {
        throw new LoginException("Oops, IOException calling handle on callbackHandler");
    } catch (UnsupportedCallbackException e) {
        throw new LoginException("Oops, UnsupportedCallbackException calling handle on callbackHandler");
    }

    NameCallback nameCallback = (NameCallback) callbacks[0];
    PasswordCallback passwordCallback = (PasswordCallback) callbacks[1];

    String name = nameCallback.getName();
    String password = new String(passwordCallback.getPassword());

    if ("sohanb".equals(name) && "welcome".equals(password)) {
        System.out.println("Success! You get to log in!");
        user = new JMXPrincipal(name);
        succeeded = true;
        return succeeded;
    } else {
        System.out.println("Failure! You don't get to log in");
        succeeded = false;
        throw new FailedLoginException("Sorry! No login for you.");
    }

      

Added: user = new JMXPrincipal(name);



Also to comment out all lines of code in the commit () nd function just add:

 subject.getPrincipals().add(user);

      

0


source







All Articles