private byte[] GetOutgoingBlob(byte[]?incomingBlob, out BlobErrorType status, out Exception?error) { try { // byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) var parameters = new object?[] { incomingBlob, false, null }; var blob = (byte[])_getOutgoingBlob.Invoke(_instance, parameters) !; var securityStatus = parameters[2]; // TODO: Update after corefx changes error = (Exception?)(_statusException.GetValue(securityStatus) ?? _getException.Invoke(null, new[] { securityStatus })); var errorCode = (SecurityStatusPalErrorCode)_statusCode.GetValue(securityStatus) !; // TODO: Remove after corefx changes // The linux implementation always uses InternalError; if (errorCode == SecurityStatusPalErrorCode.InternalError && !OperatingSystem.IsWindows() && _gssExceptionType !.IsInstanceOfType(error)) { var majorStatus = (uint)error.HResult; var minorStatus = (uint)_gssMinorStatus !.GetValue(error) !; // Remap specific errors if (majorStatus == GSS_S_NO_CRED && minorStatus == 0) { errorCode = SecurityStatusPalErrorCode.UnknownCredentials; } error = new Exception($"An authentication exception occurred (0x{majorStatus:X}/0x{minorStatus:X}).", error); } if (errorCode == SecurityStatusPalErrorCode.OK || errorCode == SecurityStatusPalErrorCode.ContinueNeeded || errorCode == SecurityStatusPalErrorCode.CompleteNeeded) { status = BlobErrorType.None; } else if (IsCredentialError(errorCode)) { status = BlobErrorType.CredentialError; } else if (IsClientError(errorCode)) { status = BlobErrorType.ClientError; } else { status = BlobErrorType.Other; } return(blob); } catch (TargetInvocationException tex) { // Unwrap ExceptionDispatchInfo.Capture(tex.InnerException !).Throw(); throw; } }
public byte[] GetOutgoingBlob(byte[] incomingBlob, out BlobErrorType status, out Exception error) { try { // byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatusPal statusCode) object[] parameters = new object[] { incomingBlob, false, null }; byte[] blob = (byte[])s_getOutgoingBlob.Invoke(_instance, parameters); object securityStatus = parameters[2]; // TODO: Update after corefx changes error = (Exception)(s_statusException.GetValue(securityStatus) ?? GetException.Invoke(null, new[] { securityStatus })); var errorCode = (NegotiateInternalSecurityStatusErrorCode)s_statusCode.GetValue(securityStatus); // TODO: Remove after corefx changes // The linux implementation always uses InternalError; if (errorCode == NegotiateInternalSecurityStatusErrorCode.InternalError && !RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && s_gssExceptionType.IsInstanceOfType(error)) { uint majorStatus = (uint)error.HResult; uint minorStatus = (uint)s_gssMinorStatus.GetValue(error); // Remap specific errors if (majorStatus == GSS_S_NO_CRED && minorStatus == 0) { errorCode = NegotiateInternalSecurityStatusErrorCode.UnknownCredentials; } error = new Exception($"An authentication exception occurred (0x{majorStatus:X}/0x{minorStatus:X}).", error); } if (errorCode == NegotiateInternalSecurityStatusErrorCode.OK || errorCode == NegotiateInternalSecurityStatusErrorCode.ContinueNeeded || errorCode == NegotiateInternalSecurityStatusErrorCode.CompleteNeeded) { status = BlobErrorType.None; } else if (IsCredentialError(errorCode)) { status = BlobErrorType.CredentialError; } else if (IsClientError(errorCode)) { status = BlobErrorType.ClientError; } else { status = BlobErrorType.Other; } return(blob); } catch (TargetInvocationException tex) { // Unwrap ExceptionDispatchInfo.Capture(tex.InnerException).Throw(); throw; } }
// Copied rather than reflected to remove the IsCompleted -> CloseContext check. // The client doesn't need the context once auth is complete, but the server does. // I'm not sure why it auto-closes for the client given that the client closes it just a few lines later. // https://github.com/dotnet/corefx/blob/a3ab91e10045bb298f48c1d1f9bd5b0782a8ac46/src/System.Net.Http/src/System/Net/Http/SocketsHttpHandler/AuthenticationHelper.NtAuth.cs#L134 public string?GetOutgoingBlob(string incomingBlob, out BlobErrorType status, out Exception?error) { byte[]? decodedIncomingBlob = null; if (incomingBlob != null && incomingBlob.Length > 0) { decodedIncomingBlob = Convert.FromBase64String(incomingBlob); } byte[] decodedOutgoingBlob = GetOutgoingBlob(decodedIncomingBlob, out status, out error); string?outgoingBlob = null; if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0) { outgoingBlob = Convert.ToBase64String(decodedOutgoingBlob); } return(outgoingBlob); }
public string GetOutgoingBlob(string incomingBlob, out BlobErrorType errorType, out Exception ex) { if (IsDisposed) { throw new ObjectDisposedException(nameof(TestNegotiateState)); } if (IsCompleted) { throw new InvalidOperationException("Authentication is already complete."); } errorType = BlobErrorType.None; ex = null; switch (incomingBlob) { case "ClientNtlmBlob1": Assert.False(Stage1Complete, nameof(Stage1Complete)); Stage1Complete = true; _protocol = "NTLM"; return("ServerNtlmBlob1"); case "ClientNtlmBlob2": Assert.True(Stage1Complete, nameof(Stage1Complete)); Assert.Equal("NTLM", _protocol); IsCompleted = true; return("ServerNtlmBlob2"); // Kerberos can require one or two stages case "ClientKerberosBlob": Assert.False(Stage1Complete, nameof(Stage1Complete)); _protocol = "Kerberos"; Stage1Complete = true; IsCompleted = true; return("ServerKerberosBlob"); case "ClientKerberosBlob1": Assert.False(Stage1Complete, nameof(Stage1Complete)); _protocol = "Kerberos"; Stage1Complete = true; return("ServerKerberosBlob1"); case "ClientKerberosBlob2": Assert.True(Stage1Complete, nameof(Stage1Complete)); Assert.Equal("Kerberos", _protocol); IsCompleted = true; return("ServerKerberosBlob2"); case "CredentialError": errorType = BlobErrorType.CredentialError; ex = new Exception("A test credential error occurred"); return(null); case "ClientError": errorType = BlobErrorType.ClientError; ex = new Exception("A test client error occurred"); return(null); case "OtherError": errorType = BlobErrorType.Other; ex = new Exception("A test other error occurred"); return(null); default: errorType = BlobErrorType.Other; ex = new InvalidOperationException(incomingBlob); return(null); } }