ユーザー名とパスワードを含むWebフォームのコンテンツを取得し、Windowsベースのドメインに対してKerberosを使用して認証するJavaベースのWebアプリケーションがあります。
KDCアドレスは、ルックアップごとに異なるIPアドレスにマップするように構成されているようです。これは、コマンドラインからpingコマンドを使用して確認できます。
呼び出しはほとんどの要求に対してすぐに応答しますが、応答は断続的に遅くなります(5〜10秒またはそれ以上)。これは、どのドメインコントローラーが使用されているかによるものと思われます。
Kerberosログをオンにしようとしましたが、ドメインコントローラーのIPアドレスが表示されません。危険なドメインコントローラーを特定するために、より詳細なログをオンにするにはどうすればよいですか?
コード抽出は、ファイルシステムからkerb.confとkerb_context.confをソースします。
Kerb.confは次のとおりです。
[libdefaults]
default_realm = EXAMPLE.COM
[realms]
CYMRU.NHS.UK = {
kdc = example.com:88
admin_server = example.com
kpasswd_server = example.com
}
Kerb_context.confは次のとおりです。
primaryLoginContext {
com.Sun.security.auth.module.Krb5LoginModule required
useTicketCache=false
refreshKrb5Config=true
debug=true;
};
ソースの例は次のとおりです。
static NadexUser executePerformLogin(String username, String password) throws LoginException {
char[] passwd = password.toCharArray();
String kerbConf = ERXFileUtilities.pathForResourceNamed("nadex/kerb.conf", "RSCorp", null);
String kerbContextConf = ERXFileUtilities.pathURLForResourceNamed("nadex/kerb_context.conf", "RSCorp", null).toExternalForm();
System.setProperty("Java.security.krb5.conf", kerbConf);
System.setProperty("Java.security.auth.login.config", kerbContextConf);
try {
LoginContext lc = new LoginContext("primaryLoginContext", new UserNamePasswordCallbackHandler(username, password));
lc.login();
return new _NadexUser(lc.getSubject());
}
catch (javax.security.auth.login.LoginException le) {
throw new LoginException("Failed to login : " + le.getLocalizedMessage(), le);
}
}
システムプロパティSun.security.krb5.debug
をtrue
に設定すると、ログを有効にできます。
Oracleドキュメント を参照してください
このような詳細なログをオンにする方法は見つかりませんでしたが、代わりに別のアプローチを採用することにしました。以下のコードは、同じディレクトリにjaas.conf構成ファイルが必要な自己完結型のアプリケーションです。
この短いテストアプリケーションで使用するjaas.confの例を次に示します。
primaryLoginContext {
com.Sun.security.auth.module.Krb5LoginModule required
useTicketCache=false
refreshKrb5Config=true
debug=false;
};
このコードは、システムプロパティSun.net.inetaddr.ttlを慎重に設定して、Java DNSルックアップの結果をキャッシュしないようにします。私の場合、DNSルックアップはリクエストごとに変更されます。これはかなり大雑把なコードですが、ネットワーク内で構成が不十分または実行されているKDCを示します。
import Java.io.BufferedReader;
import Java.io.File;
import Java.io.IOException;
import Java.io.InputStreamReader;
import Java.math.BigDecimal;
import Java.math.RoundingMode;
import Java.net.InetAddress;
import Java.net.MalformedURLException;
import Java.net.UnknownHostException;
import Java.util.Date;
import Java.util.HashMap;
import Java.util.Set;
import Java.util.Vector;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
public class TestNadex {
private static final String DEFAULT_Host = "cymru.nhs.uk";
public static void main(String[] args) {
System.setProperty("Sun.net.inetaddr.ttl", "0");
String username=null;
String password=null;
try {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("Enter username: ");
username = br.readLine().trim();
System.out.println("Enter password: ");
password = br.readLine().trim();
testHost(DEFAULT_Host, username, password);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
static void testHost(String Host, String username, String password) {
HashMap<String, Vector<Long>> results = new HashMap<String, Vector<Long>>();
for (int i=0; i<200; i++) {
InetAddress ia;
try {
ia = InetAddress.getByName(Host);
long startTime = System.currentTimeMillis();
executePerformLogin(ia.getHostAddress(), username, password);
long endTime = System.currentTimeMillis();
long duration = endTime - startTime;
if (results.containsKey(ia.toString()) == false) {
Vector<Long> v = new Vector<Long>();
v.add(duration);
results.put(ia.toString(), v);
}
else {
Vector<Long> v = results.get(ia.toString());
v.add(duration);
}
Thread.sleep(1000);
} catch (UnknownHostException e) {
System.out.println("Unknown Host: " + Host);
System.exit(1);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Set<String> keys = results.keySet();
for (String key : keys) {
System.out.println("For address: " + key);
Vector<Long> times = results.get(key);
int count = times.size();
long total = 0;
for (Long t : times) {
System.out.println(t + " milliseconds");
total += t;
}
System.out.println("Mean duration: " + new BigDecimal(total).divide(new BigDecimal(count), RoundingMode.HALF_UP));
}
}
static void executePerformLogin(String hostname, String username, String password) throws MalformedURLException {
System.setProperty("Java.security.krb5.realm", "CYMRU.NHS.UK");
System.setProperty("Java.security.krb5.kdc", hostname);
File jaas = new File("jaas.conf");
String jaasconf = jaas.toURI().toURL().toExternalForm();
System.setProperty("Java.security.auth.login.config", jaasconf);
// System.setProperty("Java.security.krb5.realm", "cymru.nhs.uk");
// System.setProperty("Java.security.krb5.kdc", "cymru.nhs.uk");
try {
System.out.println("Performing NADEX login for username: " + username + " at " + new Date() + " to server " + hostname);
LoginContext lc = new LoginContext("primaryLoginContext", new UserNamePasswordCallbackHandler(username, password));
lc.login();
System.out.println("Successful login for " + lc.getSubject().toString() + " at " + new Date());
}
catch (javax.security.auth.login.LoginException le) {
System.err.println("Failed to login: " + le);
}
}
public static class UserNamePasswordCallbackHandler implements CallbackHandler {
private final String _userName;
private final String _password;
public UserNamePasswordCallbackHandler(String userName, String password) {
_userName = userName;
_password = password;
}
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof NameCallback && _userName != null) {
((NameCallback) callback).setName(_userName);
}
else if (callback instanceof PasswordCallback && _password != null) {
((PasswordCallback) callback).setPassword(_password.toCharArray());
}
}
}
}
}