多语言展示
当前在线:522今日阅读:83今日分享:25

Java如何借助Kerberos实现身份认证

本文根据自己的实际经验介绍一下,Java如何借助Kerberos实现身份认证。Java调用接口为GSS(通用安全服务接口),实现与KDC(密钥分配中心)的信息交互及数据的加解密处理,希望本经验对使用Kerberos的人有所帮助。
工具/原料
1

Kerberos的KDC已经配置完成。

2

Eclipse开发工具

方法/步骤
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

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

推荐信息