使用 JAAS 模块时如何通过 mbean 绕过 jmx.access 文件进行身份验证

How to authenticate with mbean bypassing jmx.access file when using JAAS module

我正面临一个 mbean 身份验证问题。问题是我需要始终更改我的 mbean jmx.access 文件以匹配不同用户的授权规则。我需要以某种方式绕过此 jmx.access 文件并仅使用我的自定义 JAAS 登录模块进行身份验证,该模块仅在后端调用其余 api。

求推荐。 此外,任何其他比这更好的方法都值得赞赏!

这是我的全部代码

public class SystemConfigManagement {
private static final int    DEFAULT_NO_THREADS = 10;
private static final String DEFAULT_SCHEMA     = "default";

private static String       response           = null;

public static void main(String[] args) throws MalformedObjectNameException, InterruptedException,
        InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
    // Get the MBean server
    MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
    // register the MBean
    SystemConfig mBean = new SystemConfig(DEFAULT_NO_THREADS, DEFAULT_SCHEMA);
    ObjectName name = new ObjectName("com.sigma.jmx:type=SystemConfig");
    mbs.registerMBean(mBean, name);
    do {
        Thread.sleep(3000);
        System.out.println("Thread Count=" + mBean.getThreadCount() + ":::Schema Name="
                + mBean.getSchemaName());
        if (mBean.getSchemaName().equalsIgnoreCase("NewSchema")) {
            System.out.println("Yes, you got right shcema name with token " + mBean.getToken());
            response = RestClient.callPost("/validate-token", mBean.getToken(), "{}");
            System.out.println("Toekn validation response " + response);

            if (response.contains("\"valid\":true")) {
                System.out.println("You are Logged In....");
            } else {
                System.out.println("Your Token is invalid, you cannot login...");
            }

        } else {
            System.out.println("Schema name is invalid");
        }

    } while (mBean.getThreadCount() != 0);

}

}

JAAS 登录模块

package com.sigma.loginmodule;

import java.util.*;
import java.io.IOException;

import javax.management.remote.JMXPrincipal;
import javax.security.auth.*;
import javax.security.auth.callback.*;
import javax.security.auth.login.*;
import javax.security.auth.spi.*;

import com.sigma.loginmodule.SamplePrincipal;

public class SampleLoginModule implements LoginModule {

    private Subject         subject;
    private CallbackHandler callbackHandler;
    private Map             sharedState;
    private Map             options;
    // configurable option
    private boolean         debug           = false;
    private boolean         succeeded       = false;

    private boolean         commitSucceeded = false;

    // username and password
    private String          username;
    private char[]          password;
    private JMXPrincipal    user;
    // testUser's SamplePrincipal
    private SamplePrincipal userPrincipal;

    public SampleLoginModule() {
        System.out.println("Login Module - constructor called");
    }

    public boolean abort() throws LoginException {
        System.out.println("Login Module - abort called");

        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's commit failed
            logout();
        }
        return true;
        // return false;
    }

    public boolean commit() throws LoginException {
        System.out.println("Login Module - commit called");
        subject.getPrincipals().add(user);
        return succeeded;
    }

    public void initialize(Subject subject, CallbackHandler callbackHandler, Map<String, ?> sharedState,
            Map<String, ?> options) {

        System.out.println("Login Module - initialize called");
        this.subject = subject;
        this.callbackHandler = callbackHandler;
        this.sharedState = sharedState;
        this.options = options;

        // System.out.println("testOption value: " + (String) options.get("testOption"));
        debug = "true".equalsIgnoreCase((String) options.get("debug"));

        succeeded = false;
    }

    public boolean login() throws LoginException {
        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.");
        }

        // return true;
    }

    public boolean logout() throws LoginException {
        System.out.println("Login Module - logout called");
        return false;
    }

}

JMX 客户端代码:

package client;

import java.io.IOException;
import java.util.HashMap;
import java.util.Map;



import javax.management.MBeanServerConnection;
import javax.management.MBeanServerInvocationHandler;
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
import javax.management.remote.JMXConnector;
import javax.management.remote.JMXConnectorFactory;
import javax.management.remote.JMXServiceURL;

import com.sigma.SystemConfigMBean;


public class SystemConfigClient {

    public static final String HOST = "localhost";
    public static final String PORT = "8888";


    public static void main(String[] args) throws IOException, MalformedObjectNameException {
        JMXServiceURL url =
            new JMXServiceURL("service:jmx:rmi:///jndi/rmi://" + HOST + ":" + PORT + "/jmxrmi");
        //service:jmx:rmi:///jndi/rmi://localhost:8888/jmxrmi
        // for passing credentials for password
        Map<String, String[]> env = new HashMap<>();
        String[] credentials = { "sohanb", "welcome" };
        env.put(JMXConnector.CREDENTIALS, credentials);

        JMXConnector jmxConnector = JMXConnectorFactory.connect(url,env);
        MBeanServerConnection mbeanServerConnection = jmxConnector.getMBeanServerConnection();
        //ObjectName should be same as your MBean name
        ObjectName mbeanName = new ObjectName("com.sigma.jmx:type=SystemConfig");

        //Get MBean proxy instance that will be used to make calls to registered MBean
        SystemConfigMBean mbeanProxy =
            (SystemConfigMBean) MBeanServerInvocationHandler.newProxyInstance(
                mbeanServerConnection, mbeanName, SystemConfigMBean.class, true);

        //let's make some calls to mbean through proxy and see the results.
        System.out.println("Current SystemConfig::" + mbeanProxy.doConfig());

        String autenticate = RestClient.authenticate("handong", "welcome", true);
        System.out.println("Got autenticate Toekn id as " + autenticate);
        mbeanProxy.setToken(autenticate);
        mbeanProxy.setSchemaName("NewSchema");
        mbeanProxy.setThreadCount(5);

        System.out.println("New SystemConfig::" + mbeanProxy.doConfig());

        //let's terminate the mbean by making thread count as 0
      //  mbeanProxy.setThreadCount(0);

        //close the connection
        jmxConnector.close();
    }

}

示例 JAAS 文件:

Sample {
   com.sigma.loginmodule.SampleLoginModule required debug=true ;
};

我认为解决此问题的唯一方法是编写您自己的实现 JMXAuthenticator 的自定义 JAAS 验证器。

用于身份验证的主要身份验证方法的代码片段。 此方法调用调用我在 JAAS 身份验证器的构造函数中传递的登录模块,

 @SuppressWarnings("unchecked")
public final Subject authenticate(final Object credentials) throws SecurityException {
    Map<String, Object> myCredentials = new HashMap<String, Object>();

    if (credentials instanceof String[]) {
        // JConsole sends the credentials as string array
        // credentials[0] is the username
        // credentials[1] is the password
        String[] args = (String[]) credentials;

        if (args.length == 2) {

            myCredentials.put(USERNAME, args[0]);

            char[] pw = null;

            if (args[1] != null) {
                pw = args[1].toCharArray();
            }

            myCredentials.put(PASSWORD, pw);
        } else {
            throw new SecurityException();
        }
    } else if (credentials instanceof Map) {
        myCredentials.putAll((Map) credentials);
        if (sslEnabled && myCredentials.containsKey(CERTIFICATE)) {
            throw new SecurityException();
        }
    } else {
        throw new SecurityException();
    }

    LoginContext lc = null;

    try {
        lc = new LoginContext(systemName, new CredentialCallbackHandler(systemName, myCredentials));
        System.out.println("JAAS authenticator called ...");
    } catch (LoginException le) {
        le.printStackTrace();
    }

    try {
        lc.login();
        try {
            Subject.doAsPrivileged(lc.getSubject(), new PrintCodeBaseAndPrincipalsAction(), null);
        } catch (PrivilegedActionException ex) {
            if (ex.getException() instanceof SecurityException) {
                throw (SecurityException) ex.getException();
            } else {
                throw new SecurityException(ex.getException());
            }
        }

        return lc.getSubject();

    } catch (LoginException ex) {
        throw new SecurityException(ex);
    } catch (SecurityException ex) {
        throw ex;
    } catch (Throwable ex) {
        throw new SecurityException(ex);
    }    
}

下面是我如何调用和设置我的 JAAS 验证器构造函数,

 Map<String, Object> env = new HashMap<String, Object>();
        JAASJMXAuthenticator authenticator = new JAASJMXAuthenticator(jaasConfigName, false);
        if (authenticator != null) {
            System.out.println("JAASJMXAuthenticator is not null");
            env.put(JMXConnectorServer.AUTHENTICATOR, authenticator);
        }

希望这对以后的人有所帮助。如果需要,我可以提供完整的代码示例。

干杯!