/// <summary>
/// Initialize authentication sequence for the client
/// </summary>
/// <param name="clientToken">Payload received from the server</param>
/// <returns>Token to be sent to the server</returns>
public SSPIResponse ContinueClientAuthentication(byte[] clientToken)
{
// Wrap client token with the security buffer
SecBufferDesc serverSecBuffer = new SecBufferDesc(clientToken);
try
{
// Allocate a new instance of the client security buffer of the specified size
SecBufferDesc clientSecBuffer = new SecBufferDesc(_maxTokenBufferSize);
try
{
// Return code from the security API call
int secReturnCode = 0;
// New context attribute
uint contextAttribute = 0;
// Initialize token lifetime container
SecurityInteger lifeTime = new SecurityInteger();
// Delegate into security API
secReturnCode = SecurityWrapper.InitializeSecurityContext(ref _outboundCredential,
ref _clientContext,
_targetMachineSPN,
(int)(SecContextRequirements.MutualAuthentication | SecContextRequirements.Delegate | SecContextRequirements.ExtendedError),
0,
(int)SecDataRepresentation.Native,
ref serverSecBuffer,
0,
out _clientContext,
out clientSecBuffer,
out contextAttribute,
out lifeTime);
// Check the return code
if (secReturnCode != (int)SecResult.Ok && secReturnCode != (int)SecResult.ContinueNeeded && secReturnCode != (int)SecResult.CompleteAndContinue)
{
// Operation failed
throw new Win32Exception(secReturnCode, "Failed to generate security context");
}
// NOTE: Digest SSP call to "CompleteAuthToken" is intentionally omitted because we don't support Digest today.
// Convert to byte array and indication whether this is a last call
return(new SSPIResponse(clientSecBuffer.ToArray(), secReturnCode != (int)SecResult.ContinueNeeded && secReturnCode != (int)SecResult.CompleteAndContinue));
}
finally
{
// Dispose client security buffer
clientSecBuffer.Dispose();
}
}
finally
{
// Dispose server security buffer
serverSecBuffer.Dispose();
}
}