aspnetcore/src/Microsoft.AspNet.Security.W.../NTAuthentication.cs

739 lines
33 KiB
C#

// Copyright (c) Microsoft Open Technologies, Inc.
// All Rights Reserved
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR
// CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING
// WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF
// TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR
// NON-INFRINGEMENT.
// See the Apache 2 License for the specific language governing
// permissions and limitations under the License.
//------------------------------------------------------------------------------
// <copyright file="_NTAuthentication.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Net;
using System.Security.Authentication.ExtendedProtection;
using System.Security.Permissions;
using System.Security.Principal;
using System.Text;
using System.Threading;
namespace Microsoft.AspNet.Security.Windows
{
internal class NTAuthentication
{
private static readonly ContextCallback Callback = new ContextCallback(InitializeCallback);
private static ISSPIInterface SSPIAuth = new SSPIAuthType();
private bool _isServer;
private SafeFreeCredentials _credentialsHandle;
private SafeDeleteContext _securityContext;
private string _spn;
private string _clientSpecifiedSpn;
private int _tokenSize;
private ContextFlags _requestedContextFlags;
private ContextFlags _contextFlags;
private string _uniqueUserId;
private bool _isCompleted;
private string _protocolName;
private SecSizes _sizes;
private string _lastProtocolName;
private string _package;
private ChannelBinding _channelBinding;
// This overload does not attmept to impersonate because the caller either did it already or the original thread context is still preserved
internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding)
{
Initialize(isServer, package, credential, spn, requestedContextFlags, channelBinding);
}
// This overload always uses the default credentials for the process.
[SecurityPermission(SecurityAction.Assert, Flags = SecurityPermissionFlag.ControlPrincipal)]
internal NTAuthentication(bool isServer, string package, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding)
{
try
{
using (WindowsIdentity.Impersonate(IntPtr.Zero))
{
Initialize(isServer, package, CredentialCache.DefaultNetworkCredentials, spn, requestedContextFlags, channelBinding);
}
}
catch
{
// Avoid exception filter attacks.
throw;
}
}
// The semantic of this propoerty is "Don't call me again".
// It can be completed either with success or error
// The latest case is signalled by IsValidContext==false
internal bool IsCompleted
{
get
{
return _isCompleted;
}
}
internal bool IsValidContext
{
get
{
return !(_securityContext == null || _securityContext.IsInvalid);
}
}
internal string AssociatedName
{
get
{
if (!(IsValidContext && IsCompleted))
{
throw new Win32Exception((int)SecurityStatus.InvalidHandle);
}
string name = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext, ContextAttribute.Names) as string;
GlobalLog.Print("NTAuthentication: The context is associated with [" + name + "]");
return name;
}
}
internal bool IsConfidentialityFlag
{
get
{
return (_contextFlags & ContextFlags.Confidentiality) != 0;
}
}
internal bool IsIntegrityFlag
{
get
{
return (_contextFlags & (_isServer ? ContextFlags.AcceptIntegrity : ContextFlags.InitIntegrity)) != 0;
}
}
internal bool IsMutualAuthFlag
{
get
{
return (_contextFlags & ContextFlags.MutualAuth) != 0;
}
}
internal bool IsDelegationFlag
{
get
{
return (_contextFlags & ContextFlags.Delegate) != 0;
}
}
internal bool IsIdentifyFlag
{
get
{
return (_contextFlags & (_isServer ? ContextFlags.AcceptIdentify : ContextFlags.InitIdentify)) != 0;
}
}
internal string Spn
{
get
{
return _spn;
}
}
internal string ClientSpecifiedSpn
{
get
{
if (_clientSpecifiedSpn == null)
{
_clientSpecifiedSpn = GetClientSpecifiedSpn();
}
return _clientSpecifiedSpn;
}
}
// True indicates this instance is for Server and will use AcceptSecurityContext SSPI API
internal bool IsServer
{
get
{
return _isServer;
}
}
internal bool IsKerberos
{
get
{
if (_lastProtocolName == null)
{
_lastProtocolName = ProtocolName;
}
return (object)_lastProtocolName == (object)NegotiationInfoClass.Kerberos;
}
}
internal bool IsNTLM
{
get
{
if (_lastProtocolName == null)
{
_lastProtocolName = ProtocolName;
}
return (object)_lastProtocolName == (object)NegotiationInfoClass.NTLM;
}
}
internal string Package
{
get
{
return _package;
}
}
internal string ProtocolName
{
get
{
// NB: May return string.Empty if the auth is not done yet or failed
if (_protocolName == null)
{
NegotiationInfoClass negotiationInfo = null;
if (IsValidContext)
{
negotiationInfo = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext, ContextAttribute.NegotiationInfo) as NegotiationInfoClass;
if (IsCompleted)
{
if (negotiationInfo != null)
{
// cache it only when it's completed
_protocolName = negotiationInfo.AuthenticationPackage;
}
}
}
return negotiationInfo == null ? string.Empty : negotiationInfo.AuthenticationPackage;
}
return _protocolName;
}
}
internal SecSizes Sizes
{
get
{
GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::MaxDataSize|The context is not completed or invalid.", ValidationHelper.HashString(this));
if (_sizes == null)
{
_sizes = SSPIWrapper.QueryContextAttributes(
SSPIAuth,
_securityContext,
ContextAttribute.Sizes) as SecSizes;
}
return _sizes;
}
}
internal ChannelBinding ChannelBinding
{
get { return _channelBinding; }
}
private static void InitializeCallback(object state)
{
InitializeCallbackContext context = (InitializeCallbackContext)state;
context.ThisPtr.Initialize(context.IsServer, context.Package, context.Credential, context.Spn, context.RequestedContextFlags, context.ChannelBinding);
}
private void Initialize(bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding)
{
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor() package:" + ValidationHelper.ToString(package) + " spn:" + ValidationHelper.ToString(spn) + " flags :" + requestedContextFlags.ToString());
_tokenSize = SSPIWrapper.GetVerifyPackageInfo(SSPIAuth, package, true).MaxToken;
_isServer = isServer;
_spn = spn;
_securityContext = null;
_requestedContextFlags = requestedContextFlags;
_package = package;
_channelBinding = channelBinding;
GlobalLog.Print("Peer SPN-> '" + _spn + "'");
// check if we're using DefaultCredentials
if (credential == CredentialCache.DefaultNetworkCredentials)
{
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using DefaultCredentials");
_credentialsHandle = SSPIWrapper.AcquireDefaultCredential(
SSPIAuth,
package,
(_isServer ? CredentialUse.Inbound : CredentialUse.Outbound));
_uniqueUserId = "/S"; // save off for unique connection marking ONLY used by HTTP client
}
else if (ComNetOS.IsWin7orLater)
{
unsafe
{
SafeSspiAuthDataHandle authData = null;
try
{
SecurityStatus result = UnsafeNclNativeMethods.SspiHelper.SspiEncodeStringsAsAuthIdentity(
credential.UserName/*InternalGetUserName()*/, credential.Domain/*InternalGetDomain()*/,
credential.Password/*InternalGetPassword()*/, out authData);
if (result != SecurityStatus.OK)
{
if (Logging.On)
{
Logging.PrintError(Logging.Web, SR.GetString(SR.net_log_operation_failed_with_error, "SspiEncodeStringsAsAuthIdentity()", String.Format(CultureInfo.CurrentCulture, "0x{0:X}", (int)result)));
}
throw new Win32Exception((int)result);
}
_credentialsHandle = SSPIWrapper.AcquireCredentialsHandle(SSPIAuth,
package, (_isServer ? CredentialUse.Inbound : CredentialUse.Outbound), ref authData);
}
finally
{
if (authData != null)
{
authData.Dispose();
}
}
}
}
else
{
// we're not using DefaultCredentials, we need a
// AuthIdentity struct to contain credentials
// SECREVIEW:
// we'll save username/domain in temp strings, to avoid decrypting multiple times.
// password is only used once
string username = credential.UserName; // InternalGetUserName();
string domain = credential.Domain; // InternalGetDomain();
// ATTN:
// NetworkCredential class does not differentiate between null and "" but SSPI packages treat these cases differently
// For NTLM we want to keep "" for Wdigest.Dll we should use null.
AuthIdentity authIdentity = new AuthIdentity(username, credential.Password/*InternalGetPassword()*/, (object)package == (object)NegotiationInfoClass.WDigest && (domain == null || domain.Length == 0) ? null : domain);
_uniqueUserId = domain + "/" + username + "/U"; // save off for unique connection marking ONLY used by HTTP client
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::.ctor(): using authIdentity:" + authIdentity.ToString());
_credentialsHandle = SSPIWrapper.AcquireCredentialsHandle(
SSPIAuth,
package,
(_isServer ? CredentialUse.Inbound : CredentialUse.Outbound),
ref authIdentity);
}
}
// This will return an client token when conducted authentication on server side'
// This token can be used ofr impersanation
// We use it to create a WindowsIdentity and hand it out to the server app.
internal SafeCloseHandle GetContextToken(out SecurityStatus status)
{
GlobalLog.Assert(IsCompleted && IsValidContext, "NTAuthentication#{0}::GetContextToken|Should be called only when completed with success, currently is not!", ValidationHelper.HashString(this));
GlobalLog.Assert(IsServer, "NTAuthentication#{0}::GetContextToken|The method must not be called by the client side!", ValidationHelper.HashString(this));
if (!IsValidContext)
{
throw new Win32Exception((int)SecurityStatus.InvalidHandle);
}
SafeCloseHandle token = null;
status = (SecurityStatus)SSPIWrapper.QuerySecurityContextToken(
SSPIAuth,
_securityContext,
out token);
return token;
}
internal SafeCloseHandle GetContextToken()
{
SecurityStatus status;
SafeCloseHandle token = GetContextToken(out status);
if (status != SecurityStatus.OK)
{
throw new Win32Exception((int)status);
}
return token;
}
internal void CloseContext()
{
if (_securityContext != null && !_securityContext.IsClosed)
{
_securityContext.Dispose();
}
}
// NTAuth::GetOutgoingBlob()
// Created: 12-01-1999: L.M.
// Description:
// Accepts an incoming binary security blob and returns
// an outgoing binary security blob
internal byte[] GetOutgoingBlob(byte[] incomingBlob, bool throwOnError, out SecurityStatus statusCode)
{
GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", ((incomingBlob == null) ? "0" : incomingBlob.Length.ToString(NumberFormatInfo.InvariantInfo)) + " bytes");
List<SecurityBuffer> list = new List<SecurityBuffer>(2);
if (incomingBlob != null)
{
list.Add(new SecurityBuffer(incomingBlob, BufferType.Token));
}
if (_channelBinding != null)
{
list.Add(new SecurityBuffer(_channelBinding));
}
SecurityBuffer[] inSecurityBufferArray = null;
if (list.Count > 0)
{
inSecurityBufferArray = list.ToArray();
}
SecurityBuffer outSecurityBuffer = new SecurityBuffer(_tokenSize, BufferType.Token);
bool firstTime = _securityContext == null;
try
{
if (!_isServer)
{
// client session
statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext(
SSPIAuth,
_credentialsHandle,
ref _securityContext,
_spn,
_requestedContextFlags,
Endianness.Network,
inSecurityBufferArray,
outSecurityBuffer,
ref _contextFlags);
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
if (statusCode == SecurityStatus.CompleteNeeded)
{
SecurityBuffer[] inSecurityBuffers = new SecurityBuffer[1];
inSecurityBuffers[0] = outSecurityBuffer;
statusCode = (SecurityStatus)SSPIWrapper.CompleteAuthToken(
SSPIAuth,
ref _securityContext,
inSecurityBuffers);
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
outSecurityBuffer.token = null;
}
}
else
{
// server session
statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext(
SSPIAuth,
_credentialsHandle,
ref _securityContext,
_requestedContextFlags,
Endianness.Network,
inSecurityBufferArray,
outSecurityBuffer,
ref _contextFlags);
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
}
}
finally
{
// Assuming the ISC or ASC has referenced the credential on the first successful call,
// we want to decrement the effective ref count by "disposing" it.
// The real dispose will happen when the security context is closed.
// Note if the first call was not successfull the handle is physically destroyed here
if (firstTime && _credentialsHandle != null)
{
_credentialsHandle.Dispose();
}
}
if (((int)statusCode & unchecked((int)0x80000000)) != 0)
{
CloseContext();
_isCompleted = true;
if (throwOnError)
{
Win32Exception exception = new Win32Exception((int)statusCode);
GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "Win32Exception:" + exception);
throw exception;
}
GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "null statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
return null;
}
else if (firstTime && _credentialsHandle != null)
{
// cache until it is pushed out by newly incoming handles
SSPIHandleCache.CacheCredential(_credentialsHandle);
}
// the return value from SSPI will tell us correctly if the
// handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm
// we also have to consider the case in which SSPI formed a new context, in this case we're done as well.
if (statusCode == SecurityStatus.OK)
{
// we're sucessfully done
GlobalLog.Assert(statusCode == SecurityStatus.OK, "NTAuthentication#{0}::GetOutgoingBlob()|statusCode:[0x{1:x8}] ({2}) m_SecurityContext#{3}::Handle:[{4}] [STATUS != OK]", ValidationHelper.HashString(this), (int)statusCode, statusCode, ValidationHelper.HashString(_securityContext), ValidationHelper.ToString(_securityContext));
_isCompleted = true;
}
else
{
// we need to continue
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob() need continue statusCode:[0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(_securityContext) + "::Handle:" + ValidationHelper.ToString(_securityContext) + "]");
}
// GlobalLog.Print("out token = " + outSecurityBuffer.ToString());
// GlobalLog.Dump(outSecurityBuffer.token);
GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingBlob", "IsCompleted:" + IsCompleted.ToString());
return outSecurityBuffer.token;
}
// for Server side (IIS 6.0) see: \\netindex\Sources\inetsrv\iis\iisrearc\iisplus\ulw3\digestprovider.cxx
// for Client side (HTTP.SYS) see: \\netindex\Sources\net\http\sys\ucauth.c
internal string GetOutgoingDigestBlob(string incomingBlob, string requestMethod, string requestedUri, string realm, bool isClientPreAuth, bool throwOnError, out SecurityStatus statusCode)
{
GlobalLog.Enter("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", incomingBlob);
// second time call with 3 incoming buffers to select HTTP client.
// we should get back a SecurityStatus.OK and a non null outgoingBlob.
SecurityBuffer[] inSecurityBuffers = null;
SecurityBuffer outSecurityBuffer = new SecurityBuffer(_tokenSize, isClientPreAuth ? BufferType.Parameters : BufferType.Token);
bool firstTime = _securityContext == null;
try
{
if (!_isServer)
{
// client session
if (!isClientPreAuth)
{
if (incomingBlob != null)
{
List<SecurityBuffer> list = new List<SecurityBuffer>(5);
list.Add(new SecurityBuffer(HeaderEncoding.GetBytes(incomingBlob), BufferType.Token));
list.Add(new SecurityBuffer(HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters));
list.Add(new SecurityBuffer(null, BufferType.Parameters));
list.Add(new SecurityBuffer(Encoding.Unicode.GetBytes(_spn), BufferType.TargetHost));
if (_channelBinding != null)
{
list.Add(new SecurityBuffer(_channelBinding));
}
inSecurityBuffers = list.ToArray();
}
statusCode = (SecurityStatus)SSPIWrapper.InitializeSecurityContext(
SSPIAuth,
_credentialsHandle,
ref _securityContext,
requestedUri, // this must match the Uri in the HTTP status line for the current request
_requestedContextFlags,
Endianness.Network,
inSecurityBuffers,
outSecurityBuffer,
ref _contextFlags);
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.InitializeSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
}
else
{
#if WDIGEST_PREAUTH
inSecurityBuffers = new SecurityBuffer[] {
new SecurityBuffer(null, BufferType.Token),
new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters),
new SecurityBuffer(WebHeaderCollection.HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters),
new SecurityBuffer(null, BufferType.Parameters),
outSecurityBuffer,
};
statusCode = (SecurityStatus) SSPIWrapper.MakeSignature(GlobalSSPI.SSPIAuth, m_SecurityContext, inSecurityBuffers, 0);
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.MakeSignature() returns statusCode:0x" + ((int) statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
#else
statusCode = SecurityStatus.OK;
GlobalLog.Assert("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob()", "Invalid code path.");
#endif
}
}
else
{
// server session
List<SecurityBuffer> list = new List<SecurityBuffer>(6);
list.Add(incomingBlob == null ? new SecurityBuffer(0, BufferType.Token) : new SecurityBuffer(HeaderEncoding.GetBytes(incomingBlob), BufferType.Token));
list.Add(requestMethod == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(HeaderEncoding.GetBytes(requestMethod), BufferType.Parameters));
list.Add(requestedUri == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(HeaderEncoding.GetBytes(requestedUri), BufferType.Parameters));
list.Add(new SecurityBuffer(0, BufferType.Parameters));
list.Add(realm == null ? new SecurityBuffer(0, BufferType.Parameters) : new SecurityBuffer(Encoding.Unicode.GetBytes(realm), BufferType.Parameters));
if (_channelBinding != null)
{
list.Add(new SecurityBuffer(_channelBinding));
}
inSecurityBuffers = list.ToArray();
statusCode = (SecurityStatus)SSPIWrapper.AcceptSecurityContext(
SSPIAuth,
_credentialsHandle,
ref _securityContext,
_requestedContextFlags,
Endianness.Network,
inSecurityBuffers,
outSecurityBuffer,
ref _contextFlags);
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.AcceptSecurityContext() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
if (statusCode == SecurityStatus.CompleteNeeded)
{
inSecurityBuffers[4] = outSecurityBuffer;
statusCode = (SecurityStatus)SSPIWrapper.CompleteAuthToken(
SSPIAuth,
ref _securityContext,
inSecurityBuffers);
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() SSPIWrapper.CompleteAuthToken() returns statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
outSecurityBuffer.token = null;
}
}
}
finally
{
// Assuming the ISC or ASC has referenced the credential on the first successful call,
// we want to decrement the effective ref count by "disposing" it.
// The real dispose will happen when the security context is closed.
// Note if the first call was not successfull the handle is physically destroyed here
if (firstTime && _credentialsHandle != null)
{
_credentialsHandle.Dispose();
}
}
if (((int)statusCode & unchecked((int)0x80000000)) != 0)
{
CloseContext();
if (throwOnError)
{
Win32Exception exception = new Win32Exception((int)statusCode);
GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "Win32Exception:" + exception);
throw exception;
}
GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", "null statusCode:0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + " (" + statusCode.ToString() + ")");
return null;
}
else if (firstTime && _credentialsHandle != null)
{
// cache until it is pushed out by newly incoming handles
SSPIHandleCache.CacheCredential(_credentialsHandle);
}
// the return value from SSPI will tell us correctly if the
// handshake is over or not: http://msdn.microsoft.com/library/psdk/secspi/sspiref_67p0.htm
if (statusCode == SecurityStatus.OK)
{
// we're done, cleanup
_isCompleted = true;
}
else
{
// we need to continue
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() need continue statusCode:[0x" + ((int)statusCode).ToString("x8", NumberFormatInfo.InvariantInfo) + "] (" + statusCode.ToString() + ") m_SecurityContext#" + ValidationHelper.HashString(_securityContext) + "::Handle:" + ValidationHelper.ToString(_securityContext) + "]");
}
GlobalLog.Print("out token = " + outSecurityBuffer.ToString());
GlobalLog.Dump(outSecurityBuffer.token);
GlobalLog.Print("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob() IsCompleted:" + IsCompleted.ToString());
byte[] decodedOutgoingBlob = outSecurityBuffer.token;
string outgoingBlob = null;
if (decodedOutgoingBlob != null && decodedOutgoingBlob.Length > 0)
{
outgoingBlob = HeaderEncoding.GetString(decodedOutgoingBlob, 0, outSecurityBuffer.size);
}
GlobalLog.Leave("NTAuthentication#" + ValidationHelper.HashString(this) + "::GetOutgoingDigestBlob", outgoingBlob);
return outgoingBlob;
}
private string GetClientSpecifiedSpn()
{
GlobalLog.Assert(IsValidContext && IsCompleted, "NTAuthentication: Trying to get the client SPN before handshaking is done!");
string spn = SSPIWrapper.QueryContextAttributes(SSPIAuth, _securityContext,
ContextAttribute.ClientSpecifiedSpn) as string;
GlobalLog.Print("NTAuthentication: The client specified SPN is [" + spn + "]");
return spn;
}
private class InitializeCallbackContext
{
internal readonly NTAuthentication ThisPtr;
internal readonly bool IsServer;
internal readonly string Package;
internal readonly NetworkCredential Credential;
internal readonly string Spn;
internal readonly ContextFlags RequestedContextFlags;
internal readonly ChannelBinding ChannelBinding;
internal InitializeCallbackContext(NTAuthentication thisPtr, bool isServer, string package, NetworkCredential credential, string spn, ContextFlags requestedContextFlags, ChannelBinding channelBinding)
{
this.ThisPtr = thisPtr;
this.IsServer = isServer;
this.Package = package;
this.Credential = credential;
this.Spn = spn;
this.RequestedContextFlags = requestedContextFlags;
this.ChannelBinding = channelBinding;
}
}
}
}