public IWindowsSecurityContext acceptSecurityToken(final String connectionId, final byte[] token,
final String securityPackage) {
if (token == null || token.length == 0) {
this.continueContexts.asMap().remove(connectionId);
throw new Win32Exception(WinError.SEC_E_INVALID_TOKEN);
}
final IWindowsCredentialsHandle serverCredential = new WindowsCredentialsHandleImpl(null,
Sspi.SECPKG_CRED_INBOUND, securityPackage);
serverCredential.initialize();
WindowsSecurityContextImpl sc;
int rc;
int tokenSize = Sspi.MAX_TOKEN_SIZE;
CtxtHandle continueContext;
SecBufferDesc pbServerToken;
SecBufferDesc pbClientToken;
final IntByReference pfClientContextAttr = new IntByReference();
final CtxtHandle phNewServerContext = new CtxtHandle();
do {
pbServerToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, tokenSize);
pbClientToken = new SecBufferDesc(Sspi.SECBUFFER_TOKEN, token);
continueContext = this.continueContexts.asMap().get(connectionId);
rc = Secur32.INSTANCE.AcceptSecurityContext(serverCredential.getHandle(), continueContext, pbClientToken,
Sspi.ISC_REQ_CONNECTION, Sspi.SECURITY_NATIVE_DREP, phNewServerContext, pbServerToken,
pfClientContextAttr, null);
sc = new WindowsSecurityContextImpl();
sc.setCredentialsHandle(serverCredential.getHandle());
sc.setSecurityPackage(securityPackage);
sc.setSecurityContext(phNewServerContext);
switch (rc) {
case WinError.SEC_E_BUFFER_TOO_SMALL:
tokenSize += Sspi.MAX_TOKEN_SIZE;
sc.dispose();
WindowsSecurityContextImpl.dispose(continueContext);
break;
case WinError.SEC_E_OK:
// the security context received from the client was accepted
this.continueContexts.asMap().remove(connectionId);
// if an output token was generated by the function, it must be sent to the client process
if (pbServerToken.pBuffers != null && pbServerToken.cBuffers == 1
&& pbServerToken.pBuffers[0].cbBuffer > 0) {
sc.setToken(pbServerToken.getBytes() == null ? new byte[0] : pbServerToken.getBytes().clone());
}
sc.setContinue(false);
break;
case WinError.SEC_I_CONTINUE_NEEDED:
// the server must send the output token to the client and wait for a returned token
this.continueContexts.put(connectionId, phNewServerContext);
sc.setToken(pbServerToken.getBytes() == null ? new byte[0] : pbServerToken.getBytes().clone());
sc.setContinue(true);
break;
default:
sc.dispose();
WindowsSecurityContextImpl.dispose(continueContext);
this.continueContexts.asMap().remove(connectionId);
throw new Win32Exception(rc);
}
} while (rc == WinError.SEC_E_BUFFER_TOO_SMALL);
return sc;
}