该API返回一个用于接受的安全环境,在此时刻,该安全环境并不知道要与之连接的客户端名称以及底层所使用的安全机制。然而,一旦到来的请求不符合服务器的principal或者底层安全机制不相符的话,连接就会失败。
在GSSContext可以提供安全服务之前必须先在两个对等实体之间完成token的交换。每次调用GSSContext的establishment方法都会产生一个不透明的token,应用服务器必须将这个token传送给对等实体。
客户端使用下述API确立安全环境:
byte[]GSSContext.initSecContext(byte[] inToken,
int offset,
int len)
throws GSSException
服务器使用另一个API:
byte[]acceptSecContext(byte[] inToken,
int offset,
int len)
throws GSSException
这两个方法是补足的。一个方法的输出是另一个方法的输入。客户端第一次调用initSecContext的时候产生第一个token,最后一个token的产生依赖于选择的底层安全机制以及其属性设置。
GSS-APItoken来回传递的次数随底层安全机制的不同而不同,并且和安全机制单向认证还是双向认证相关。因此,客户端和服务器都要持续调用安全环境establishment方法,直到这个过程结束。
在底层安全机制为kerberos v5的情况下,安全环境的确立要经过多个步骤。首先客户端使用initSecContext方法生成一个token,并包含一个kerberos AP-REQ消息。为了建立这个消息,客户端使用自身的TGT请求一个serviceticket,该service ticket由服务器端长期密钥加密并封装到AP-REQ消息中。服务器收到这个token之后,把它传递到acceptSecContext方法中解密service ticket并认证客户端。如果不需要双向认证,此时安全环境确立成功,acceptSecContext方法不产生返回值。如果需要双向认证,上述方法会产生一个token,并封装到AP-REP消息中。这个消息会送到initSecContext方法中,之后双方安全环境确立成功。
注意GSSContext在客户端初始化的时候,它是明确底层的安全机制的,GSS-API框架会获得一个合适的安全机制的实例。之后,所有对GSSContext的请求都被安全机制的实例代理。在服务器端,直到客户端的第一个token到达之后,才确定底层安全机制。
下面是客户端和服务器的例子:
【Client】
classClientAction implements PrivilegedAction {
public Object run() {
...
...
try {
GSSManager manager = GSSManager.getInstance();
GSSName clientName =
manager.createName("duke", GSSName.NT_USER_NAME);
GSSCredential clientCreds =
manager.createCredential(clientName,
8*3600,
desiredMechs,
GSSCredential.INITIATE_ONLY);
GSSName peerName =
manager.createName("nfs@bar.foo.com",
GSSName.NT_HOSTBASED_SERVICE);
GSSContext secContext =
manager.createContext(peerName,
krb5Oid,
clientCreds,
GSSContext.DEFAULT_LIFETIME);
secContext.requestMutualAuth(true);
// The first input token is ignored
byte[] inToken = new byte[0];
byte[] outToken = null;
boolean established = false;
// Loop while the context is still not established
while (!established) {
outToken =
secContext.initSecContext(inToken, 0, inToken.length);
// Send a token to the peer if one was generated
if (outToken != null)
sendToken(outToken);
if (!secContext.isEstablished()) {
inToken = readToken();
else
established = true;
}
} catch (GSSException e) {
....
}
...
...
}
}
【Server】
classServerAction implelemts PrivilegedAction {
public Object run() {
...
...
try {
GSSManager manager = GSSManager.getInstance();
GSSName serverName =
manager.createName("nfs@bar.foo.com",
GSSName.NT_HOSTBASED_SERVICE);
GSSCredential serverCreds =
manager.createCredential(serverName,
GSSCredential.INDEFINITE_LIFETIME,
desiredMechs,
GSSCredential.ACCEPT_ONLY);
GSSContext secContext = manager.createContext(serverCreds);
byte[] inToken = null;
byte[] outToken = null;
// Loop while the context is still not established
while (!secContext.isEstablished()) {
inToken = readToken();
outToken =
secContext.acceptSecContext(inToken, 0, inToken.length);
// Send a token to the peer if one was generated
if (outToken != null)
sendToken(outToken);
}
} catch (GSSException e) {
...
}
...
...
}
}
MessageProtection
一旦安全环境确立之后,双方可以开始安全通信,Java GSS-API提供双方的消息完整性和机密性保障。下面两个方法实现这组功能:
byte[]GSSContext.wrap(byte[] clearText,
int offset,
int len,
MessageProp properties)
throws GSSException
byte[]unwrap(byte[] inToken,
int offset,
int len,
MessageProp properties)
throws GSSException