Java如何借助Kerberos实现身份认证
1、分别为客户端和服务端创建登录KDC的用户。
使用kadmin.local工具。
#kadmin.local
#kadmin.local: addprinc sample/qibaofu.com@QIBAOFU.COM
#kadmin.local: addprinc test1/qibaofu.com@QIBAOFU.COM
创建完成后,查看用户:
客户端为:test1,服务端为:sample

2、使用ping查看配置的主机名是否正常。此例子中,主机名为qibaofu.com,若是出现如下结果,则证明配置是正确的。

3、编写客户端程序。
import org.ietf.jgss.*;
import java.net.Socket;
import java.io.IOException;
import java.io.DataInputStream;
import java.io.DataOutputStream;
public class SampleClient {
public static void main(String[] args)
throws IOException, GSSException {
System.setProperty("java.security.krb5.realm","QIBAOFU.COM");
System.setProperty("java.security.krb5.kdc","qibaofu.com");
System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
System.setProperty("java.security.auth.login.config","bcsLogin.conf");
String server = "sample/qibaofu.com";
String hostName = "127.0.0.1";
int port = 8090;
Socket socket = new Socket(hostName, port);
DataInputStream inStream =
new DataInputStream(socket.getInputStream());
DataOutputStream outStream =
new DataOutputStream(socket.getOutputStream());
System.out.println("Connected to server "
+ socket.getInetAddress());
Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
GSSManager manager = GSSManager.getInstance();
GSSName serverName = manager.createName(server, null);
GSSContext context = manager.createContext(serverName,
krb5Oid,
null,
GSSContext.DEFAULT_LIFETIME);
context.requestMutualAuth(true); // Mutual authentication
context.requestConf(true); // Will use confidentiality later
context.requestInteg(true); // Will use integrity later
// Do the context eastablishment loop
byte[] token = new byte[0];
while (!context.isEstablished()) {
// token is ignored on the first call
token = context.initSecContext(token, 0, token.length);
// Send a token to the server if one was generated by
// initSecContext
if (token != null) {
System.out.println("Will send token of size "
+ token.length
+ " from initSecContext.");
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
}
// If the client is done with context establishment
// then there will be no more tokens to read in this loop
if (!context.isEstablished()) {
token = new byte[inStream.readInt()];
System.out.println("Will read input token of size "
+ token.length
+ " for processing by initSecContext");
inStream.readFully(token);
}
}
System.out.println("Context Established! ");
System.out.println("Client is " + context.getSrcName());
System.out.println("Server is " + context.getTargName());
if (context.getMutualAuthState())
System.out.println("Mutual authentication took place!");
byte[] messageBytes = "Hello There!\0".getBytes();
MessageProp prop = new MessageProp(0, true);
token = context.wrap(messageBytes, 0, messageBytes.length, prop);
System.out.println("Will send wrap token of size " + token.length);
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
token = new byte[inStream.readInt()];
System.out.println("Will read token of size " + token.length);
inStream.readFully(token);
context.verifyMIC(token, 0, token.length,
messageBytes, 0, messageBytes.length,
prop);
System.out.println("Verified received MIC for message.");
System.out.println("Exiting...");
context.dispose();
socket.close();
}
}

4、编写服务端程序。
import org.ietf.jgss.*;
import java.io.*;
import java.net.Socket;
import java.net.ServerSocket;
public class SampleServer {
public static void main(String[] args)
throws IOException, GSSException {
System.setProperty("java.security.krb5.realm","QIBAOFU.COM");
System.setProperty("java.security.krb5.kdc","qibaofu.com");
System.setProperty("javax.security.auth.useSubjectCredsOnly","false");
System.setProperty("java.security.auth.login.config","bcsLogin.conf");
int localPort = 8090;
ServerSocket ss = new ServerSocket(localPort);
GSSManager manager = GSSManager.getInstance();
while (true) {
System.out.println("Waiting for incoming connection...");
Socket socket = ss.accept();
DataInputStream inStream =
new DataInputStream(socket.getInputStream());
DataOutputStream outStream =
new DataOutputStream(socket.getOutputStream());
System.out.println("Got connection from client "
+ socket.getInetAddress());
GSSContext context = manager.createContext((GSSCredential)null);
// Do the context eastablishment loop
byte[] token = null;
while (!context.isEstablished()) {
token = new byte[inStream.readInt()];
System.out.println("Will read input token of size "
+ token.length
+ " for processing by acceptSecContext");
inStream.readFully(token);
token = context.acceptSecContext(token, 0, token.length);
// Send a token to the peer if one was generated by
// acceptSecContext
if (token != null) {
System.out.println("Will send token of size "
+ token.length
+ " from acceptSecContext.");
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
}
}
System.out.print("Context Established! ");
System.out.println("Client is " + context.getSrcName());
System.out.println("Server is " + context.getTargName());
if (context.getMutualAuthState())
System.out.println("Mutual authentication took place!");
MessageProp prop = new MessageProp(0, false);
token = new byte[inStream.readInt()];
System.out.println("Will read token of size "
+ token.length);
inStream.readFully(token);
byte[] bytes = context.unwrap(token, 0, token.length, prop);
String str = new String(bytes);
System.out.println("Received data \""
+ str + "\" of length " + str.length());
System.out.println("Confidentiality applied: "
+ prop.getPrivacy());
prop.setQOP(0);
token = context.getMIC(bytes, 0, bytes.length, prop);
System.out.println("Will send MIC token of size "
+ token.length);
outStream.writeInt(token.length);
outStream.write(token);
outStream.flush();
System.out.println("Closing connection with client "
+ socket.getInetAddress());
context.dispose();
socket.close();
}
}
}

5、启动服务端程序,然后接着启动客户端程序。


6、执行客户端程序后,会提示输入用户名和密码,客户端输入后,会接着提示服务端也输入,因为此程序为互相认证,所以服务端也需要输入用户名和密码。


7、服务端输入密码后,此时可以发现服务可以正常执行完毕。

