現在、Java GSS で使用可能なセキュリティーメカニズムは「Kerberos」のみです。この課題の目標は、SPNEGO などのほかの Java GSS メカニズムを使用してセキュアに関連付けを行う方法について学習することです。この機能は、Java SE 6 以降で使用できます。
SPNEGO とは
Java GSS は、複数のセキュリティーメカニズムをサポートするフレームワークです。GSS-API の下でセキュリティーメカニズムとネゴシエーションを行う方法が必要となります。これは、SPNEGO を介して使用できます。
SPNEGO は、IETF の RFC 4178 で標準化されている Simple and Protected GSS-API Negotiation メカニズムです。これは、ベースとなるセキュリティーメカニズムとのネゴシエーションを行う場合に使用する擬似セキュリティーメカニズムです。SPNEGO を使用すると、クライアントとサーバーに柔軟性が付与され、共通の GSS セキュリティーメカニズムとセキュアにネゴシエーションを行うことができます。
Microsoft は SPNEGO を多用しています。SPNEGO は、HTTP を介して Microsoft サーバーと相互運用したり、Negotiate プロトコルを介して HTTP ベースのクロスプラットフォーム認証をサポートしたりする場合に使用されます。
Java GSS で SPNEGO を使用する場合に行う必要がある設定
現在、Kerberos とともに Java GSS を使用する場合は、Kerberos OID を指定して Kerberos を使用します。
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
SPNEGO を使用するには、次のように SPNEGO OID
を指定するだけで済みます。
Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
そのあと、GSSCredential、GSSContext などを作成する際に SPNEGO OID
を使用します。
src/GssSpNegoClient.java
にありますGssSpNegoClient.java
のコードリスト。
static class GssSpnegoClientAction implements PrivilegedExceptionAction {
...
public Object run() throws Exception {
// Create socket to server
Socket socket = new Socket(hostName, port);
DataInputStream inStream = new DataInputStream(socket.getInputStream());
DataOutputStream outStream = new DataOutputStream(socket.getOutputStream());
// Get service's principal name
GSSManager manager = GSSManager.getInstance();
Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
GSSName serverName = manager.createName(serverPrinc, GSSName.NT_HOSTBASED_SERVICE, spnegoOid);
// Get the context for authentication
GSSContext context = manager.createContext(serverName, spnegoOid, null,
GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true); // Request mutual authentication
context.requestConf(true); // Request confidentiality
// Do the context establishment loop
byte[] token = new byte[0];
while (!context.isEstablished()) {
token = context.initSecContext(token, 0, token.length);
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
// Check if we're done
if (!context.isEstablished()) {
token = new byte[inStream.readInt()];
inStream.readFully(token);
}
}
// Context established!
// Create MessageProp for use with unwrap (true means request confidentiality)
MessageProp prop = new MessageProp(0, true);
// Create encrypted message and send to server
byte[] reply = ...;
token = context.wrap(reply, 0, reply.length, prop);
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
// Read token from server
token = new byte[inStream.readInt()];
inStream.readFully(token);
// Unwrap (decrypt) token sent by server
byte[] input = context.unwrap(token, 0, token.length, prop);
...
context.dispose();
socket.close();
return null;
}
}
% javac GssSpNegoClient.java
src/GssSpNegoServer.java
にありますGssSpNegoServer.java
のコードリスト。
static class GssSpNegoServerAction implements PrivilegedExceptionAction {
...
public Object run() throws Exception {
// Create server socket for accepting connections
ServerSocket ss = new ServerSocket(localPort);
// Get own Kerberos credentials for accepting connection
GSSManager manager = GSSManager.getInstance();
Oid spnegoOid = new Oid("1.3.6.1.5.5.2");
GSSCredential serverCreds = manager.createCredential(null,
GSSCredential.DEFAULT_LIFETIME, spnegoOid, GSSCredential.ACCEPT_ONLY);
while (true) {
Socket socket = ss.accept();
DataInputStream inStream = new DataInputStream(socket.getInputStream());
DataOutputStream outStream = new DataOutputStream(socket.getOutputStream());
GSSContext context = manager.createContext((GSSCredential)serverCreds);
// Do the context establishment loop
byte[] token = null;
while (!context.isEstablished()) {
// Read token
token = new byte[inStream.readInt()];
inStream.readFully(token);
// Process token
token = context.acceptSecContext(token, 0, token.length);
// Send a token to the peer if one was generated by acceptSecContext
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
}
// Context established!
// Create MessageProp for use with unwrap (will be set upon return from unwrap)
MessageProp prop = new MessageProp(0, false);
// Read token from client
token = new byte[inStream.readInt()];
inStream.readFully(token);
// Unwrap (decrypt) token sent by client
byte[] input = context.unwrap(token, 0, token.length, prop);
...
// Create new token and send to client
byte[] reply = ...;
token = context.wrap(reply, 0, reply.length, prop);
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
context.dispose();
socket.close();
}
}
}
% javac GssSpNegoServer.java
% xterm & % java -Djava.security.auth.login.config=jaas-krb5.conf GssSpNegoServer
j1hol-001
上で実行されている host
の場合は、次のように入力します。パスワードの入力を求められた場合は、changeit を入力します。
% java -Djava.security.auth.login.config=jaas-krb5.conf \ GssSpNegoClient host j1hol-001
GssSpNegoServer
の例を実行した場合の出力。
Authenticated principal: [host/j1hol-001@J1LABS.EXAMPLE.COM]
Waiting for incoming connections...
Got connection from client /129.145.128.102
Context Established!
Client principal is test@J1LABS.EXAMPLE.COM
Server principal is host/j1hol-001@J1LABS.EXAMPLE.COM
Mutual authentication took place!
Received data "Hello There!" of length 12
Confidentiality applied: true
Sending: Hello There! Thu May 06 12:11:15 PDT 2005
GssSpNegoClient
の例を実行した場合の出力。
Kerberos password for test: changeit
Authenticated principal: [test@J1LABS.EXAMPLE.COM]
Connected to address j1hol-001/129.145.128.102
Context Established!
Client principal is test@J1LABS.EXAMPLE.COM
Server principal is host@j1hol-001
Mutual authentication took place!
Sending message: Hello There!
Will read token of size 93
Received message: Hello There! Thu May 06 12:11:15 PDT 2005
サマリー:
この課題では、Kerberos などのベースとなるセキュリティーメカニズムとネゴシエーションを行い、ベースとなる認証システムとして Kerberos を使用してセキュアに通信を行うために SPNEGO とともに Java GSS API を使用するクライアント/サーバーアプリケーションを記述する方法について学習しました。
注: Microsoft は特定のバリエーションの SPNEGO プロトコルを実装しています。このため、Microsoft と相互運用を行うために、新しいシステムプロパティー「sun.security.spnego.msinterop」を使用して MS モードを追加しました。このプロパティーは、デフォルトで「true」になっています。無効にするには、このプロパティーを明示的に「false」に設定する必要があります。SPNEGO デバッグを有効にするには、システムプロパティー「sun.security.spnego.debug=true」を設定します。