如何加密JConsole密码文件的密码 [英] How to encrypt passwords for JConsole's password file

查看:122
本文介绍了如何加密JConsole密码文件的密码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用JConsole访问我的应用程序MBean,我使用的是password.properties文件。但是根据Sun的规范,此文件仅包含明文格式的密码。



com.sun.management.jmxremote.password.file =< someLocation> /password.properties



现在我想加密密码,并将其用于JConsole的JMX用户身份验证(Remote部分中的用户名和密码字段)。我可以使用任何预定义的加密逻辑或我自己的加密算法。有没有人知道任何这样的拦截将明文密码更改为加密密码,以便JMX框架也知道加密的密码?



我当前的密码文件:

 客人
admin admin

加密应该是这样的:



$ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $ $¬$您可以使用配置参数 com.sun.management.jmxremote.login.config 在management.properties文件(请参阅%JAVA_HOME%/ lib / management / management.properties)来配置要使用的Authenticator和LoginModule。



默认值为:

  JMXPluggableAuthenticator {
com.sun.jmx.remote.security.FileLoginModule required;
};

它读取纯文本密码文件 jmxremote.password 。由于 com.sun.jmx.remote.security.JMXPluggableAuthenticator 可以重新配置
以使用任何LoginModule实现,您可以自由选择现有的LoginModule或实现您自己的
,它使用加密的密码文件。



要重新实现 FileLoginModule ,您应该看看在 attemptAuthentication(boolean)方法中,
实际执行身份验证,您可能要替换它。实现 javax.security.auth.spi.LoginModule interface
,并使用给定的CallbackHandler(您将从init()方法获取)来请求一个用户名和密码。加密/散列接收的密码,并将其与从您的加密密码文件中读取的密码进行比较。伪代码:

  public class EncryptedFileLoginModule implements LoginModule {

@Override
public void initialize (Subject subject,CallbackHandler callbackHandler,
Map< String,?> sharedState,Map< String,?> options){
this.subject = subject;
this.callbackHandler = callbackHandler;
}

public boolean login()throws LoginException {
attemptLogin();
if(username == null || password == null){
throw new LoginException(无用户名或无密码指定);
}
MessageDigest instance = MessageDigest.getInstance(SHA-1);
byte [] raw = new String(password).getBytes();
byte [] crypted = instance.digest(raw);
// TODO:比较本地存储的
if(!authenticated)throw new LoginException();
返回true;
}

private void attemptLogin()throws LoginException {
回调[] callbacks = new回调[2];
callbacks [0] = new NameCallback(username);
callbacks [1] = new PasswordCallback(password,false);
callbackHandler.handle(callbacks);
username =((NameCallback)callbacks [0])。getName();
user = new JMXPrincipal(username);
char [] tmpPassword =((PasswordCallback)callbacks [1])。getPassword();
password = new char [tmpPassword.length];
System.arraycopy(tmpPassword,0,password,0,tmpPassword.length);
((PasswordCallback)callbacks [1])。clearPassword();
}

但是,由于这已经是服务器端,所以密码将不可用如果您不执行
JMX over SSL,仍然以纯文本形式传输。所以,要么执行SSL,要么使用另一个传输协议机制,它可以在
通过电话传输之前对其进行编码。



总而言之,对JAAS提供的现有认证机制。例如,如果您在本地Windows环境中运行
,则可以轻松地使用 NTLoginModule 进行自动登录。但是它只适用于本地机器。



创建文件c:/temp/mysecurity.cfg:

  MyLoginModule {
com.sun.security.auth.module.NTLoginModule REQUIRED debug = true debugNative = true;
};

接下来,配置jmxremote.access文件以包含您希望授予访问权限的用户名或角色JMX服务器:

  monitorRole readonly 
controlRole readwrite ...
mhaller readonly

(我建议启用调试模式,直到它工作,当用户可以看到所有的用户名,域名和组名尝试登录)
为您的服务器设置以下JVM参数:

  -Dcom.sun.management.jmxremote 
-Dcom.sun.management.jmxremote.port = 8686
-Dcom.sun.management.jmxremote.authenticate = true
-Dcom.sun.management.jmxremote.ssl = true
-Djava.net.preferIPv4Stack = true
-Djava.security.auth.login.config = c:/temp/mysecurity.cfg
-Dcom.sun.management.jmxremote.login.config = MyLoginModule

启动应用程序并尝试使用JConsole或VisualVM进行连接。



请注意,JConsole,你w不好的是需要指定用户名和密码,尽管它不会被使用。任何密码和任何用户名都可以使用。
原因是因为jconsole会尝试使用null用户名和空密码进行身份验证,这将被明确阻止。
当用户没有输入用户名和密码时,VisualVM可以使用空字符串做更好的工作。



另请注意,连接时NTLoginModule不起作用远程的,我想你必须使用一个更复杂的登录模块
,但Sun已经提供了足够的:




  • com.sun.security.auth.module.Krb5LoginModule:使用Kerberos协议验证用户

  • com.sun.security.auth.module.LdapLoginModule: (Java 6中的新增功能):通过指定技术连接用户

  • com.sun.security.auth.module.JndiLoginModule:对在JNDI上下文中注册的LDAP服务器执行身份验证

  • com.sun.security.auth.module.KeyStoreLoginModule :使用Java密钥库验证用户身份。支持PIN或智能卡认证。



您将看到 LdapLoginModule

>

I am using the JConsole to access my application MBeans and i use the the password.properties file. But as per the Sun's specification this file contains passwords in clear text formats only.

com.sun.management.jmxremote.password.file=<someLocation>/password.properties

Now i would want to encrypt the password and use it for the JMX user authentication from JConsole (the username and password fields in Remote section). I could use any pre-defined encryption logic or my own encryption algorithms.

Does anyone know of any such interception to change the plain text password to encrypted one so that the JMX Framework too knows about the encrypted password?

My Current password file:

guest  guest
admin  admin

With Encryption it should look like:

guest  ENC(RjqpRYbAOwbAfAEDBdHJ7Q4l/GO5IoJidZctNT5oG64=)
admin  ENC(psg3EnDei6fVRuqHeLwOqNTgIWkwQTjI2+u2O7MXXWc=)

解决方案

You can use the configuration parameter com.sun.management.jmxremote.login.config in the management.properties file (see %JAVA_HOME%/lib/management/management.properties) to configure which Authenticator and LoginModule to use.

The default is the following:

JMXPluggableAuthenticator {
    com.sun.jmx.remote.security.FileLoginModule required;
};

which reads plain text password file jmxremote.password. Since the com.sun.jmx.remote.security.JMXPluggableAuthenticator can be reconfigured to use any LoginModule implementation, you are free to either choose an existing LoginModule or to implement your own which uses encrypted password files.

To reimplement FileLoginModule, you should have a look at the attemptAuthentication(boolean) method, which actually performs the authentication and which you probably are going to replace. Implement the javax.security.auth.spi.LoginModule interface and use the given CallbackHandler (you will get it from the init() method) to ask for a username and password. Encrypt/hash the received password and compare it against the one read from your encrypted password file. Pseudo code:

public class EncryptedFileLoginModule implements LoginModule {

@Override
public void initialize(Subject subject, CallbackHandler callbackHandler,
        Map<String, ?> sharedState, Map<String, ?> options) {
    this.subject = subject;
    this.callbackHandler = callbackHandler;
}

public boolean login() throws LoginException {
    attemptLogin();
    if (username == null || password == null) {
        throw new LoginException("Either no username or no password specified");
    }
    MessageDigest instance = MessageDigest.getInstance("SHA-1");
    byte[] raw = new String(password).getBytes();
    byte[] crypted = instance.digest(raw);
    // TODO: Compare to the one stored locally
    if (!authenticated) throw new LoginException();
    return true;
}

private void attemptLogin() throws LoginException {
    Callback[] callbacks = new Callback[2];
    callbacks[0] = new NameCallback("username");
    callbacks[1] = new PasswordCallback("password", false);
        callbackHandler.handle(callbacks);
        username = ((NameCallback) callbacks[0]).getName();
        user = new JMXPrincipal(username);
        char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
        password = new char[tmpPassword.length];
        System.arraycopy(tmpPassword, 0, password, 0, tmpPassword.length);
        ((PasswordCallback) callbacks[1]).clearPassword();
}

However, as this is already the server-side, the password would afaik be still transferred in plain text if you don't enforce JMX over SSL. So, either enforce SSL or use another transport protocol mechanism which encodes the credentials before transmitting them over the wire.

To conclude, it's perhaps much better to rely on existing authentication mechanisms provided by JAAS. If, for example, you're running in a local Windows environment, you can easily use the NTLoginModule for auto-login. But it only works on local machine.

Create a file c:/temp/mysecurity.cfg:

MyLoginModule {
 com.sun.security.auth.module.NTLoginModule REQUIRED  debug=true debugNative=true;
};

Next, configure the jmxremote.access file to contain the usernames or roles you wish to grant access to your JMX server:

monitorRole readonly
controlRole readwrite ...
mhaller readonly

(I recommend to enable debug mode until it works. You will see all the user names, domain names and group names when a user tries to log in) Set the following JVM arguments for your server:

-Dcom.sun.management.jmxremote
-Dcom.sun.management.jmxremote.port=8686
-Dcom.sun.management.jmxremote.authenticate=true
-Dcom.sun.management.jmxremote.ssl=true
-Djava.net.preferIPv4Stack=true
-Djava.security.auth.login.config=c:/temp/mysecurity.cfg
-Dcom.sun.management.jmxremote.login.config=MyLoginModule

Start up your application and try to connect using JConsole or VisualVM.

Note that JConsole, you will need to specify a username and a password, although it's not going to be used. Any password and any username will work. The reason is because jconsole will try to authenticate with null username and null password, which is blocked explicitly. VisualVM does a better job by using empty strings for username and password when none are entered by the user.

Also note that the NTLoginModule does not work when connecting remotely, i think you would have to use a more sophisticated login module, but Sun already provides enough of them:

  • com.sun.security.auth.module.Krb5LoginModule: Authenticates users using the Kerberos protocols
  • com.sun.security.auth.module.LdapLoginModule: (new in Java 6): Performs authentication against an LDAP server by specifying technical connection user
  • com.sun.security.auth.module.JndiLoginModule: Performs authentication against an LDAP server registered in the JNDI context
  • com.sun.security.auth.module.KeyStoreLoginModule: Authenticates users by using a Java Keystore. Supports PIN or smart card authentication.

You will want to have a look at the LdapLoginModule

这篇关于如何加密JConsole密码文件的密码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆