1. JaaS コード
JAAS の使用については上記で説明しました. このセクションでは, 主に認証中の JAAS のコード フローを分析します. 認証プロセスには 2 行のコードしかないことがわかります.
LoginContext lc = new LoginContext("JaaSSampleTest", new TextCallbackHandler());
lc.login();
コンテキスト設定、ログインの 2 つの部分に分けることができます。
1.1 コンテキスト設定
LoginContext lc = new LoginContext("JaaSSampleTest", new TextCallbackHandler());
プログラムはまず、jaas.conf を介して JaaSSampleTest に対応するクラスを取得します。
JaaSSampleTest {
com.sun.security.auth.module.Krb5LoginModule required;
};
jaas.conf 構成ファイルから、対応するクラスが Krb5LoginModule であることがわかります。Krb5LoginModule のクラスを確認します。
public void initialize(Subject subject,
CallbackHandler callbackHandler,
Map<String, ?> sharedState,
Map<String, ?> options) {
this.subject = subject;
this.callbackHandler = callbackHandler;
... ...
つまり、Krb5LoginModule が初期化されると、TextCallbackHandler のハンドルが設定されます。その handle() メソッドは後で呼び出されます
1.2 ログインプロセス
プログラムが LoginContext を作成すると、
lc.login()
LoginContext.login() のコードから、主なアクションは次のとおりであることがわかります。
invokePriv(LOGIN_METHOD);
invokePriv(COMMIT_METHOD);
最初に呼び出される Krb5LoginModule::login() を見てみましょう
public boolean login() throws LoginException {
int len;
//首先校验参数信息
validateConfiguration();
... ...
if (tryFirstPass) {
try {
//此函数会根据需求获取对应的TGT信息。这其中有两种情况:
//1. 用户执行完kinit之后,会保存对应的TGT信息到对应的文件中。这个文件位置由krb5.conf中的default_ccache_name进行定义 。 程序会直接读取这个文件信息而获取TGT信息
//2. 第二种情况,如果用户不希望直接通过配置文件获取,就可以通过直接发送消息的方式获取对应的TGT信息。
//其相应的代码在:KrbAsReqBuilder::action()中
attemptAuthentication(true);
... ...
}
実際、login() の主なアクションは、関数 attemptsAuthentication() を実行することです。この関数の主なアクションは、TGT 情報を取得することです。AttemptAuthentication() では、CallbackHandler::handle() 関数にコールバックして、ユーザー名とパスワードを処理します。
commit() の機能をもう一度見てみましょう.commit の機能については、プログラムのコメントに次の段落があります。
/* * Let us add the Krb5 Creds to the Subject's * private credentials. The credentials are of type * KerberosKey or KerberosTicket */
そのコードから、前の login() の cred をサブジェクトに設定することもわかります。
1.3 まとめ
jaas 認証プロセス全体をもう一度整理してみましょう。これは、次の手順に分けることができます。
次の 2 つの部分を含む LoginContext のコンテキストを初期化します。
- 実際に対応するコンテキスト Moudle を jaas.conf から読み取り、
- CallbackHandler を Module に設定します。この CallbackHanlder::handler() の最も重要な機能は、
名前とパスワードの処理です。
login() メソッドを呼び出します。この login() メソッドは、次の 3 つのステップに分けることができます。
- Moudle の login() メソッドをコールバックする
- Module メソッドでは、CallbackHandler の handler メソッドがコールバックされます。
- 最後はMoudleのコミットメソッドをコールバックすることです
2 パスワードの非対話型ログイン
KDC の認証には、キータブ方式とパスワード方式の 2 つの方式があることがわかっています。Krb5LoginModule は、直接ログインするための keytab を提供しますが、パスワード ログインを完了するために使用することはできません。ユーザー名とパスワードを使用して非対話的にログインする方法は次のとおりです
public class JaasTestPassword {
public static void main(String[] args) {
String username = args[0];
String passwd = args[1];
Krb5Configuration conf = new Krb5Configuration();
try {
LoginContext lc = new LoginContext("JaaSSampleTest",
new Subject(),
JaasTestPassword.createJaasCallbackHandler(username,
passwd), conf);
lc.login();
Subject sub = lc.getSubject();
} catch (LoginException le) {
System.err.println("Authentication failed:");
System.exit(-1);
}
System.out.println("Authentication succeeded!");
}
public static CallbackHandler createJaasCallbackHandler(
final String principal, final String password) {
return new CallbackHandler() {
public void handle(Callback[] callbacks) throws IOException,
UnsupportedCallbackException {
for (Callback callback : callbacks) {
if (callback instanceof NameCallback) {
NameCallback nameCallback = (NameCallback) callback;
nameCallback.setName(principal);
} else if (callback instanceof PasswordCallback) {
PasswordCallback passwordCallback = (PasswordCallback) callback;
passwordCallback.setPassword(password.toCharArray());
} else {
throw new UnsupportedCallbackException(callback,
"Unsupported callback: "
+ callback.getClass()
.getCanonicalName());
}
}
}
};
}
}
構成ファイルのコード:
public class Krb5Configuration extends Configuration {
private AppConfigurationEntry[] entry = new AppConfigurationEntry[1];
Map paramMap = new HashMap();
private AppConfigurationEntry krb5LoginModule = new AppConfigurationEntry(
"com.sun.security.auth.module.Krb5LoginModule",
LoginModuleControlFlag.REQUIRED, paramMap);
@Override
public AppConfigurationEntry[] getAppConfigurationEntry(String name) {
// TODO Auto-generated method stub
if (entry[0] == null) {
paramMap.put("debug", "false"); //是否打印debug日志
paramMap.put("storeKey", "true");
paramMap.put("doNotPrompt", "false"); //直接使用密码登录,设置为false
paramMap.put("useTicketCache", "false"); //是否使用ticket
entry[0] = krb5LoginModule;
}
return entry;
}
}
3. まとめ
- JaaS ログイン全体は、LogContext、Config 構成情報、および CallBackHandler の 3 つの部分に分けることができます。その中で、Config は指定されたログイン方法 (キータブまたはキャッシュ) などの情報を構成し、CallBackHandler は handler() メソッドを使用して KDC 認証に必要な情報 (プリンシパル情報、パスワードまたはキータブなど) を対応する構成に設定します。これにより、認証が完了します
- login() 全体で、TGT は KDC から取得され、commit() は実際に TGT をサブジェクトに入力します。これには、クライアントとサーバー間の対話はまったく含まれません。