Java 针对本地 SASL 的身份验证
Java authentication against local SASL
我正在尝试制作一个 java class 以便根据本地 SASL 对用户进行身份验证。我的 saslauthd 配置是这样的:
$ cat /etc/sysconfig/saslauthd
# Directory in which to place saslauthd's listening socket, pid file, and so
# on. This directory must already exist.
SOCKETDIR=/run/saslauthd
# Mechanism to use when checking passwords. Run "saslauthd -v" to get a list
# of which mechanism your installation was compiled with the ablity to use.
MECH=pam
# Additional flags to pass to saslauthd on the command line. See saslauthd(8)
# for the list of accepted flags.
FLAGS="-t 1"
基本上它会重定向针对 PAM 的身份验证。所以,如果我正在做这样的测试。
testsaslauthd -s login -u <user> -p <password>
0: OK "Success."
一切正常。
我现在想通过Java来管理这个机制,所以我编译了这样的东西:
import java.util.Arrays;
import java.util.List;
import java.io.*;
public class PamAuthenticator {
public static void main(String args[]) {
String s = null;
try {
Process p = Runtime.getRuntime().exec("testsaslauthd -s "+args[2]+" -u "+args[0]+" -p "+args[1]);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
System.exit(0);
}
catch (IOException e) {
System.out.println("Exception: ");
e.printStackTrace();
System.exit(-1);
}
}
}
这是正确的:
$ java -cp .:* PamAuthenticator <user> <password> login
0: OK "Success."
我的问题是我不想执行 testsaslauthd
命令,因为这只是一个测试命令。为了使用 java 再次尝试 SASL 身份验证,我可以做一些更好更聪明的事情吗?
你的方向是正确的,不要使用上面的代码。除了作为测试解决方案外,它还会引入严重的安全问题:command injection
.
从 Java 1.6
开始,有一个名为 SaslClient
. This does exactly what you need. An example on the JDK8 版本的接口:
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;
import java.util.HashMap;
public class Test {
public static void main(String[] args) throws SaslException {
String userName = "username";
String password = "password";
SaslClient saslClient = Sasl.createSaslClient(new String[]{"PLAIN"},
null, null, null, new HashMap<>(), callbacks -> {
for (final Callback callback : callbacks) {
if (callback instanceof NameCallback) {
NameCallback.class.cast(callback).setName(userName);
continue;
}
if (callback instanceof PasswordCallback) {
PasswordCallback.class.cast(callback).setPassword(password.toCharArray());
continue;
}
throw new UnsupportedCallbackException(callback);
}
});
}
}
当然你应该改变用户名和密码的来源。
我正在尝试制作一个 java class 以便根据本地 SASL 对用户进行身份验证。我的 saslauthd 配置是这样的:
$ cat /etc/sysconfig/saslauthd
# Directory in which to place saslauthd's listening socket, pid file, and so
# on. This directory must already exist.
SOCKETDIR=/run/saslauthd
# Mechanism to use when checking passwords. Run "saslauthd -v" to get a list
# of which mechanism your installation was compiled with the ablity to use.
MECH=pam
# Additional flags to pass to saslauthd on the command line. See saslauthd(8)
# for the list of accepted flags.
FLAGS="-t 1"
基本上它会重定向针对 PAM 的身份验证。所以,如果我正在做这样的测试。
testsaslauthd -s login -u <user> -p <password>
0: OK "Success."
一切正常。
我现在想通过Java来管理这个机制,所以我编译了这样的东西:
import java.util.Arrays;
import java.util.List;
import java.io.*;
public class PamAuthenticator {
public static void main(String args[]) {
String s = null;
try {
Process p = Runtime.getRuntime().exec("testsaslauthd -s "+args[2]+" -u "+args[0]+" -p "+args[1]);
BufferedReader stdInput = new BufferedReader(new
InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new
InputStreamReader(p.getErrorStream()));
while ((s = stdInput.readLine()) != null) {
System.out.println(s);
}
while ((s = stdError.readLine()) != null) {
System.out.println(s);
}
System.exit(0);
}
catch (IOException e) {
System.out.println("Exception: ");
e.printStackTrace();
System.exit(-1);
}
}
}
这是正确的:
$ java -cp .:* PamAuthenticator <user> <password> login
0: OK "Success."
我的问题是我不想执行 testsaslauthd
命令,因为这只是一个测试命令。为了使用 java 再次尝试 SASL 身份验证,我可以做一些更好更聪明的事情吗?
你的方向是正确的,不要使用上面的代码。除了作为测试解决方案外,它还会引入严重的安全问题:command injection
.
从 Java 1.6
开始,有一个名为 SaslClient
. This does exactly what you need. An example on the JDK8 版本的接口:
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.sasl.Sasl;
import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;
import java.util.HashMap;
public class Test {
public static void main(String[] args) throws SaslException {
String userName = "username";
String password = "password";
SaslClient saslClient = Sasl.createSaslClient(new String[]{"PLAIN"},
null, null, null, new HashMap<>(), callbacks -> {
for (final Callback callback : callbacks) {
if (callback instanceof NameCallback) {
NameCallback.class.cast(callback).setName(userName);
continue;
}
if (callback instanceof PasswordCallback) {
PasswordCallback.class.cast(callback).setPassword(password.toCharArray());
continue;
}
throw new UnsupportedCallbackException(callback);
}
});
}
}
当然你应该改变用户名和密码的来源。