internal static SecurityStatusPal InitializeSecurityContext( ref SafeFreeCredentials credentialsHandle, ref SafeDeleteContext?securityContext, string?spn, ContextFlagsPal requestedContextFlags, byte[]?incomingBlob, ChannelBinding?channelBinding, ref byte[]?resultBlob, ref ContextFlagsPal contextFlags) { SafeFreeNegoCredentials negoCredentialsHandle = (SafeFreeNegoCredentials)credentialsHandle; if (negoCredentialsHandle.IsDefault && string.IsNullOrEmpty(spn)) { throw new PlatformNotSupportedException(SR.net_nego_not_supported_empty_target_with_defaultcreds); } SecurityStatusPal status = EstablishSecurityContext( negoCredentialsHandle, ref securityContext, channelBinding, spn, requestedContextFlags, incomingBlob, ref resultBlob, ref contextFlags); // Confidentiality flag should not be set if not requested if (status.ErrorCode == SecurityStatusPalErrorCode.CompleteNeeded) { ContextFlagsPal mask = ContextFlagsPal.Confidentiality; if ((requestedContextFlags & mask) != (contextFlags & mask)) { throw new PlatformNotSupportedException(SR.net_nego_protection_level_not_supported); } } return(status); }
private void Initialize(bool isServer, string package, NetworkCredential credential, string?spn, ContextFlagsPal requestedContextFlags, ChannelBinding?channelBinding) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this, package, spn, requestedContextFlags); } _tokenSize = NegotiateStreamPal.QueryMaxTokenSize(package); _isServer = isServer; _spn = spn; _securityContext = null; _requestedContextFlags = requestedContextFlags; _package = package; _channelBinding = channelBinding; if (NetEventSource.IsEnabled) { NetEventSource.Info(this, $"Peer SPN-> '{_spn}'"); } // // Check if we're using DefaultCredentials. // Debug.Assert(CredentialCache.DefaultCredentials == CredentialCache.DefaultNetworkCredentials); if (credential == CredentialCache.DefaultCredentials) { if (NetEventSource.IsEnabled) { NetEventSource.Info(this, "using DefaultCredentials"); } _credentialsHandle = NegotiateStreamPal.AcquireDefaultCredential(package, _isServer); } else { _credentialsHandle = NegotiateStreamPal.AcquireCredentialsHandle(package, _isServer, credential); } }
internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string?spn, ContextFlagsPal requestedContextFlags, ChannelBinding?channelBinding) { if (isServer) { throw new PlatformNotSupportedException(SR.net_nego_server_not_supported); } if (package.Equals("NTLM", StringComparison.OrdinalIgnoreCase)) { _isSpNego = false; } else if (package.Equals("Negotiate", StringComparison.OrdinalIgnoreCase)) { _isSpNego = true; } else { throw new PlatformNotSupportedException(SR.net_securitypackagesupport); } if (string.IsNullOrWhiteSpace(credential.UserName) || string.IsNullOrWhiteSpace(credential.Password)) { // NTLM authentication is not possible with default credentials which are no-op throw new PlatformNotSupportedException(SR.net_ntlm_not_possible_default_cred); } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(this, $"package={package}, spn={spn}, requestedContextFlags={requestedContextFlags}"); } _credential = credential; _spn = spn; _channelBinding = channelBinding; _contextFlags = requestedContextFlags; IsServer = isServer; }
public virtual IAsyncResult BeginAuthenticateAsClient( NetworkCredential credential, ChannelBinding?binding, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel, AsyncCallback?asyncCallback, object?asyncState) { #if DEBUG using (DebugThreadTracking.SetThreadKind(ThreadKinds.User | ThreadKinds.Async)) { #endif _negoState.ValidateCreateContext(_package, false, credential, targetName, binding, requiredProtectionLevel, allowedImpersonationLevel); LazyAsyncResult result = new LazyAsyncResult(_negoState, asyncState, asyncCallback); _negoState.ProcessAuthentication(result); return(result); #if DEBUG } #endif }
public virtual IAsyncResult BeginAuthenticateAsClient( NetworkCredential credential, ChannelBinding?binding, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel, AsyncCallback?asyncCallback, object?asyncState) => TaskToApm.Begin(AuthenticateAsClientAsync(credential, binding, targetName, requiredProtectionLevel, allowedImpersonationLevel), asyncCallback, asyncState);
public virtual IAsyncResult BeginAuthenticateAsClient(NetworkCredential credential, ChannelBinding?binding, string targetName, AsyncCallback?asyncCallback, object?asyncState) => BeginAuthenticateAsClient(credential, binding, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification, asyncCallback, asyncState);
public virtual Task AuthenticateAsClientAsync(NetworkCredential credential, ChannelBinding?binding, string targetName) { return(Task.Factory.FromAsync(BeginAuthenticateAsClient, EndAuthenticateAsClient, credential, binding, targetName, null)); }
public static IChannelBinding?ToInterface(this ChannelBinding?binding) { return((binding == null) ? null : new ChannelBindingAdapter(binding)); }
public Authorization?Authenticate(string?challenge, NetworkCredential?credential, object sessionCookie, string?spn, ChannelBinding?channelBindingToken) { lock (_sessions) { NegotiateAuthentication?clientContext; if (!_sessions.TryGetValue(sessionCookie, out clientContext)) { if (credential == null) { return(null); } _sessions[sessionCookie] = clientContext = new NegotiateAuthentication( new NegotiateAuthenticationClientOptions { Credential = credential, TargetName = spn, Binding = channelBindingToken }); } NegotiateAuthenticationStatusCode statusCode; string?resp = clientContext.GetOutgoingBlob(challenge, out statusCode); if (statusCode != NegotiateAuthenticationStatusCode.Completed && statusCode != NegotiateAuthenticationStatusCode.ContinueNeeded) { return(null); } if (!clientContext.IsAuthenticated) { return(new Authorization(resp, false)); } else { _sessions.Remove(sessionCookie); clientContext.Dispose(); return(new Authorization(resp, true)); } } }
public Authorization?Authenticate(string?challenge, NetworkCredential?credential, object sessionCookie, string?spn, ChannelBinding?channelBindingToken) { try { lock (_sessions) { NTAuthentication?clientContext; if (!_sessions.TryGetValue(sessionCookie, out clientContext)) { if (credential == null) { return(null); } _sessions[sessionCookie] = clientContext = new NTAuthentication(false, "Ntlm", credential, spn, ContextFlagsPal.Connection, channelBindingToken); } string?resp = clientContext.GetOutgoingBlob(challenge); if (!clientContext.IsCompleted) { return(new Authorization(resp, false)); } else { _sessions.Remove(sessionCookie); return(new Authorization(resp, true)); } } } // From reflected type NTAuthentication in System.Net.Security. catch (NullReferenceException) { return(null); } }
private static async Task <HttpResponseMessage> SendWithNtAuthAsync(HttpRequestMessage request, Uri authUri, bool async, ICredentials credentials, bool isProxyAuth, HttpConnection connection, HttpConnectionPool connectionPool, CancellationToken cancellationToken) { HttpResponseMessage response = await InnerSendAsync(request, async, isProxyAuth, connectionPool, connection, cancellationToken).ConfigureAwait(false); if (!isProxyAuth && connection.Kind == HttpConnectionKind.Proxy && !ProxySupportsConnectionAuth(response)) { // Proxy didn't indicate that it supports connection-based auth, so we can't proceed. if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(connection, $"Proxy doesn't support connection-based auth, uri={authUri}"); } return(response); } if (TryGetAuthenticationChallenge(response, isProxyAuth, authUri, credentials, out AuthenticationChallenge challenge)) { if (challenge.AuthenticationType == AuthenticationType.Negotiate || challenge.AuthenticationType == AuthenticationType.Ntlm) { bool isNewConnection = false; bool needDrain = true; try { if (response.Headers.ConnectionClose.GetValueOrDefault()) { // Server is closing the connection and asking us to authenticate on a new connection. // First, detach the current connection from the pool. This means it will no longer count against the connection limit. // Instead, it will be replaced by the new connection below. connection.DetachFromPool(); connection = await connectionPool.CreateHttp11ConnectionAsync(request, async, cancellationToken).ConfigureAwait(false); connection !.Acquire(); isNewConnection = true; needDrain = false; } if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, Uri: {authUri.AbsoluteUri}"); } // Calculate SPN (Service Principal Name) using the host name of the request. // Use the request's 'Host' header if available. Otherwise, use the request uri. // Ignore the 'Host' header if this is proxy authentication since we need to use // the host name of the proxy itself for SPN calculation. string hostName; if (!isProxyAuth && request.HasHeaders && request.Headers.Host != null) { // Use the host name without any normalization. hostName = request.Headers.Host; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, Host: {hostName}"); } } else { // Need to use FQDN normalized host so that CNAME's are traversed. // Use DNS to do the forward lookup to an A (host) record. // But skip DNS lookup on IP literals. Otherwise, we would end up // doing an unintended reverse DNS lookup. UriHostNameType hnt = authUri.HostNameType; if (hnt == UriHostNameType.IPv6 || hnt == UriHostNameType.IPv4) { hostName = authUri.IdnHost; } else { IPHostEntry result = await Dns.GetHostEntryAsync(authUri.IdnHost, cancellationToken).ConfigureAwait(false); hostName = result.HostName; } if (!isProxyAuth && !authUri.IsDefaultPort && UsePortInSpn) { hostName = string.Create(null, stackalloc char[128], $"{hostName}:{authUri.Port}"); } } string spn = "HTTP/" + hostName; if (NetEventSource.Log.IsEnabled()) { NetEventSource.Info(connection, $"Authentication: {challenge.AuthenticationType}, SPN: {spn}"); } ChannelBinding? channelBinding = connection.TransportContext?.GetChannelBinding(ChannelBindingKind.Endpoint); NTAuthentication authContext = new NTAuthentication(isServer: false, challenge.SchemeName, challenge.Credential, spn, ContextFlagsPal.Connection | ContextFlagsPal.InitIntegrity, channelBinding); string? challengeData = challenge.ChallengeData; try { while (true) { string?challengeResponse = authContext.GetOutgoingBlob(challengeData); if (challengeResponse == null) { // Response indicated denial even after login, so stop processing and return current response. break; } if (needDrain) { await connection.DrainResponseAsync(response !, cancellationToken).ConfigureAwait(false); } SetRequestAuthenticationHeaderValue(request, new AuthenticationHeaderValue(challenge.SchemeName, challengeResponse), isProxyAuth); response = await InnerSendAsync(request, async, isProxyAuth, connectionPool, connection, cancellationToken).ConfigureAwait(false); if (authContext.IsCompleted || !TryGetRepeatedChallenge(response, challenge.SchemeName, isProxyAuth, out challengeData)) { break; } needDrain = true; } } finally { authContext.CloseContext(); } } finally { if (isNewConnection) { connection !.Release(); } } } } return(response !); }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials?credentialsHandle, ref SafeDeleteContext?securityContext, ContextFlagsPal requestedContextFlags, ReadOnlySpan <byte> incomingBlob, ChannelBinding?channelBinding, ref byte[] resultBlob, out int resultBlobLength, ref ContextFlagsPal contextFlags) { securityContext ??= new SafeDeleteNegoContext((SafeFreeNegoCredentials)credentialsHandle !); SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)securityContext; SafeGssContextHandle contextHandle = negoContext.GssContext; Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer); try { Interop.NetSecurityNative.Status status; Interop.NetSecurityNative.Status minorStatus; status = Interop.NetSecurityNative.AcceptSecContext(out minorStatus, negoContext.AcceptorCredential, ref contextHandle, incomingBlob, ref token, out uint outputFlags, out bool isNtlmUsed); if ((status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) && (status != Interop.NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED)) { if (negoContext.GssContext.IsInvalid) { contextHandle.Dispose(); } Interop.NetSecurityNative.GssApiException gex = new Interop.NetSecurityNative.GssApiException(status, minorStatus); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, gex); } resultBlobLength = 0; return(new SecurityStatusPal(GetErrorCode(gex), gex)); } resultBlob = token.ToByteArray(); Debug.Assert(resultBlob != null, "Unexpected null buffer returned by GssApi"); contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop( (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: true); resultBlobLength = resultBlob.Length; SecurityStatusPalErrorCode errorCode; if (status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE) { if (NetEventSource.Log.IsEnabled()) { string protocol = isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos"; NetEventSource.Info(securityContext, $"AcceptSecurityContext: actual protocol = {protocol}"); } negoContext.SetAuthenticationPackage(isNtlmUsed); errorCode = SecurityStatusPalErrorCode.OK; } else { errorCode = SecurityStatusPalErrorCode.ContinueNeeded; } return(new SecurityStatusPal(errorCode)); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, ex); } resultBlobLength = 0; return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } finally { token.Dispose(); // Save the inner context handle for further calls to NetSecurity // // For the first call `negoContext.GssContext` is invalid and we expect the // inital handle to be returned from AcceptSecContext. For any subsequent // call the handle should stay the same or it can be destroyed by the native // AcceptSecContext call. Debug.Assert( negoContext.GssContext == contextHandle || negoContext.GssContext.IsInvalid || contextHandle.IsInvalid); negoContext.SetGssContext(contextHandle); } }
private static SecurityStatusPal EstablishSecurityContext( SafeFreeNegoCredentials credential, ref SafeDeleteContext?context, ChannelBinding?channelBinding, string?targetName, ContextFlagsPal inFlags, ReadOnlySpan <byte> incomingBlob, out byte[]?resultBuffer, ref ContextFlagsPal outFlags) { bool isNtlmOnly = credential.IsNtlmOnly; resultBuffer = null; if (context == null) { if (NetEventSource.Log.IsEnabled()) { string protocol = isNtlmOnly ? "NTLM" : "SPNEGO"; NetEventSource.Info(context, $"requested protocol = {protocol}, target = {targetName}"); } context = new SafeDeleteNegoContext(credential, targetName !); } Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer); Interop.NetSecurityNative.Status status; Interop.NetSecurityNative.Status minorStatus; SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context; SafeGssContextHandle contextHandle = negoContext.GssContext; try { Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer: false); uint outputFlags; bool isNtlmUsed; if (channelBinding != null) { // If a TLS channel binding token (cbt) is available then get the pointer // to the application specific data. int appDataOffset = Marshal.SizeOf <SecChannelBindings>(); Debug.Assert(appDataOffset < channelBinding.Size); IntPtr cbtAppData = channelBinding.DangerousGetHandle() + appDataOffset; int cbtAppDataSize = channelBinding.Size - appDataOffset; status = Interop.NetSecurityNative.InitSecContext(out minorStatus, credential.GssCredential, ref contextHandle, isNtlmOnly, cbtAppData, cbtAppDataSize, negoContext.TargetName, (uint)inputFlags, incomingBlob, ref token, out outputFlags, out isNtlmUsed); } else { status = Interop.NetSecurityNative.InitSecContext(out minorStatus, credential.GssCredential, ref contextHandle, isNtlmOnly, negoContext.TargetName, (uint)inputFlags, incomingBlob, ref token, out outputFlags, out isNtlmUsed); } if ((status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) && (status != Interop.NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED)) { if (negoContext.GssContext.IsInvalid) { context.Dispose(); } Interop.NetSecurityNative.GssApiException gex = new Interop.NetSecurityNative.GssApiException(status, minorStatus); if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, gex); } resultBuffer = Array.Empty <byte>(); return(new SecurityStatusPal(GetErrorCode(gex), gex)); } resultBuffer = token.ToByteArray(); if (status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE) { if (NetEventSource.Log.IsEnabled()) { string protocol = isNtlmOnly ? "NTLM" : isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos"; NetEventSource.Info(context, $"actual protocol = {protocol}"); } // Populate protocol used for authentication negoContext.SetAuthenticationPackage(isNtlmUsed); } Debug.Assert(resultBuffer != null, "Unexpected null buffer returned by GssApi"); outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop( (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false); SecurityStatusPalErrorCode errorCode = status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.ContinueNeeded; return(new SecurityStatusPal(errorCode)); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, ex); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } finally { token.Dispose(); // Save the inner context handle for further calls to NetSecurity // // For the first call `negoContext.GssContext` is invalid and we expect the // inital handle to be returned from InitSecContext. For any subsequent // call the handle should stay the same or it can be destroyed by the native // InitSecContext call. Debug.Assert( negoContext.GssContext == contextHandle || negoContext.GssContext.IsInvalid || contextHandle.IsInvalid); negoContext.SetGssContext(contextHandle); } }
public Authorization?Authenticate(string?challenge, NetworkCredential?credential, object sessionCookie, string?spn, ChannelBinding?channelBindingToken) { lock (_sessions) { NegotiateAuthentication?clientContext; if (!_sessions.TryGetValue(sessionCookie, out clientContext)) { if (credential == null) { return(null); } ProtectionLevel protectionLevel = ProtectionLevel.Sign; // Workaround for https://github.com/gssapi/gss-ntlmssp/issues/77 // GSSAPI NTLM SSP does not support gss_wrap/gss_unwrap unless confidentiality // is negotiated. if (OperatingSystem.IsLinux()) { protectionLevel = ProtectionLevel.EncryptAndSign; } _sessions[sessionCookie] = clientContext = new NegotiateAuthentication( new NegotiateAuthenticationClientOptions { Credential = credential, TargetName = spn, RequiredProtectionLevel = protectionLevel, Binding = channelBindingToken }); } string?resp = null; NegotiateAuthenticationStatusCode statusCode; if (!clientContext.IsAuthenticated) { // If auth is not yet completed keep producing // challenge responses with GetOutgoingBlob resp = clientContext.GetOutgoingBlob(challenge, out statusCode); if (statusCode != NegotiateAuthenticationStatusCode.Completed && statusCode != NegotiateAuthenticationStatusCode.ContinueNeeded) { return(null); } if (clientContext.IsAuthenticated && resp == null) { resp = "\r\n"; } } else { // If auth completed and still have a challenge then // server may be doing "correct" form of GSSAPI SASL. // Validate incoming and produce outgoing SASL security // layer negotiate message. resp = GetSecurityLayerOutgoingBlob(challenge, clientContext); } return(new Authorization(resp, clientContext.IsAuthenticated)); } }
public Authorization?Authenticate(string?challenge, NetworkCredential?credential, object sessionCookie, string?spn, ChannelBinding?channelBindingToken) { if (NetEventSource.IsEnabled) { NetEventSource.Enter(this); } try { lock (_sessions) { NetworkCredential?cachedCredential; if (!_sessions.TryGetValue(sessionCookie, out cachedCredential)) { if (credential == null || ReferenceEquals(credential, CredentialCache.DefaultNetworkCredentials)) { return(null); } _sessions[sessionCookie] = credential; string userName = credential.UserName; string domain = credential.Domain; if (domain != null && domain.Length > 0) { userName = domain + "\\" + userName; } return(new Authorization(Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(userName)), false)); } else { _sessions.Remove(sessionCookie); return(new Authorization(Convert.ToBase64String(System.Text.Encoding.UTF8.GetBytes(cachedCredential.Password)), true)); } } } finally { if (NetEventSource.IsEnabled) { NetEventSource.Exit(this); } } }
public Authorization?Authenticate(string?challenge, NetworkCredential?credential, object sessionCookie, string?spn, ChannelBinding?channelBindingToken) { try { lock (_sessions) { NTAuthentication?clientContext; if (!_sessions.TryGetValue(sessionCookie, out clientContext)) { if (credential == null) { return(null); } _sessions[sessionCookie] = clientContext = new NTAuthentication(false, "Negotiate", credential, spn, ContextFlagsPal.Connection | ContextFlagsPal.InitIntegrity, channelBindingToken); } byte[]? byteResp; string?resp = null; if (!clientContext.IsCompleted) { // If auth is not yet completed keep producing // challenge responses with GetOutgoingBlob byte[]? decodedChallenge = null; if (challenge != null) { decodedChallenge = Convert.FromBase64String(challenge); } byteResp = clientContext.GetOutgoingBlob(decodedChallenge, false); if (clientContext.IsCompleted && byteResp == null) { resp = "\r\n"; } if (byteResp != null) { resp = Convert.ToBase64String(byteResp); } } else { // If auth completed and still have a challenge then // server may be doing "correct" form of GSSAPI SASL. // Validate incoming and produce outgoing SASL security // layer negotiate message. resp = GetSecurityLayerOutgoingBlob(challenge, clientContext); } return(new Authorization(resp, clientContext.IsCompleted)); } } // From reflected type NTAuthentication in System.Net.Security. catch (NullReferenceException) { return(null); } }
public virtual void AuthenticateAsClient( NetworkCredential credential, ChannelBinding?binding, string targetName, ProtectionLevel requiredProtectionLevel, TokenImpersonationLevel allowedImpersonationLevel) { ValidateCreateContext(DefaultPackage, isServer: false, credential, targetName, binding, requiredProtectionLevel, allowedImpersonationLevel); AuthenticateAsync(new SyncReadWriteAdapter(InnerStream)).GetAwaiter().GetResult(); }
internal static SecurityStatusPal AcceptSecurityContext( SafeFreeCredentials?credentialsHandle, ref SafeDeleteContext?securityContext, ContextFlagsPal requestedContextFlags, byte[]?incomingBlob, ChannelBinding?channelBinding, ref byte[] resultBlob, ref ContextFlagsPal contextFlags) { if (securityContext == null) { securityContext = new SafeDeleteNegoContext((SafeFreeNegoCredentials)credentialsHandle !); } SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)securityContext; try { SafeGssContextHandle?contextHandle = negoContext.GssContext; bool done = GssAcceptSecurityContext( ref contextHandle, negoContext.AcceptorCredential, incomingBlob, out resultBlob, out uint outputFlags, out bool isNtlmUsed); Debug.Assert(resultBlob != null, "Unexpected null buffer returned by GssApi"); Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); // Save the inner context handle for further calls to NetSecurity Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); if (null == negoContext.GssContext) { negoContext.SetGssContext(contextHandle !); } contextFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop( (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: true); SecurityStatusPalErrorCode errorCode; if (done) { if (NetEventSource.Log.IsEnabled()) { string protocol = isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos"; NetEventSource.Info(securityContext, $"AcceptSecurityContext: actual protocol = {protocol}"); } negoContext.SetAuthenticationPackage(isNtlmUsed); errorCode = (isNtlmUsed && resultBlob.Length > 0) ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded; } else { errorCode = SecurityStatusPalErrorCode.ContinueNeeded; } return(new SecurityStatusPal(errorCode)); } catch (Interop.NetSecurityNative.GssApiException gex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, gex); } return(new SecurityStatusPal(GetErrorCode(gex), gex)); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, ex); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } }
public virtual Task AuthenticateAsClientAsync(NetworkCredential credential, ChannelBinding?binding, string targetName) => AuthenticateAsClientAsync(credential, binding, targetName, ProtectionLevel.EncryptAndSign, TokenImpersonationLevel.Identification);
internal void ValidateCreateContext( string package, bool isServer, NetworkCredential credential, string?servicePrincipalName, ChannelBinding?channelBinding, ProtectionLevel protectionLevel, TokenImpersonationLevel impersonationLevel) { if (_exception != null && !_canRetryAuthentication) { ExceptionDispatchInfo.Throw(_exception); } if (_context != null && _context.IsValidContext) { throw new InvalidOperationException(SR.net_auth_reauth); } if (credential == null) { throw new ArgumentNullException(nameof(credential)); } if (servicePrincipalName == null) { throw new ArgumentNullException(nameof(servicePrincipalName)); } NegotiateStreamPal.ValidateImpersonationLevel(impersonationLevel); if (_context != null && IsServer != isServer) { throw new InvalidOperationException(SR.net_auth_client_server); } _exception = null; _remoteOk = false; _framer = new StreamFramer(_innerStream); _framer.WriteHeader.MessageId = FrameHeader.HandshakeId; _expectedProtectionLevel = protectionLevel; _expectedImpersonationLevel = isServer ? impersonationLevel : TokenImpersonationLevel.None; _writeSequenceNumber = 0; _readSequenceNumber = 0; ContextFlagsPal flags = ContextFlagsPal.Connection; // A workaround for the client when talking to Win9x on the server side. if (protectionLevel == ProtectionLevel.None && !isServer) { package = NegotiationInfoClass.NTLM; } else if (protectionLevel == ProtectionLevel.EncryptAndSign) { flags |= ContextFlagsPal.Confidentiality; } else if (protectionLevel == ProtectionLevel.Sign) { // Assuming user expects NT4 SP4 and above. flags |= (ContextFlagsPal.ReplayDetect | ContextFlagsPal.SequenceDetect | ContextFlagsPal.InitIntegrity); } if (isServer) { if (_extendedProtectionPolicy !.PolicyEnforcement == PolicyEnforcement.WhenSupported) { flags |= ContextFlagsPal.AllowMissingBindings; } if (_extendedProtectionPolicy.PolicyEnforcement != PolicyEnforcement.Never && _extendedProtectionPolicy.ProtectionScenario == ProtectionScenario.TrustedProxy) { flags |= ContextFlagsPal.ProxyBindings; } } else { // Server side should not request any of these flags. if (protectionLevel != ProtectionLevel.None) { flags |= ContextFlagsPal.MutualAuth; } if (impersonationLevel == TokenImpersonationLevel.Identification) { flags |= ContextFlagsPal.InitIdentify; } if (impersonationLevel == TokenImpersonationLevel.Delegation) { flags |= ContextFlagsPal.Delegate; } } _canRetryAuthentication = false; try { _context = new NTAuthentication(isServer, package, credential, servicePrincipalName, flags, channelBinding !); } catch (Win32Exception e) { throw new AuthenticationException(SR.net_auth_SSPI, e); } }
private static SecurityStatusPal EstablishSecurityContext( SafeFreeNegoCredentials credential, ref SafeDeleteContext?context, ChannelBinding?channelBinding, string?targetName, ContextFlagsPal inFlags, byte[]?incomingBlob, ref byte[]?resultBuffer, ref ContextFlagsPal outFlags) { bool isNtlmOnly = credential.IsNtlmOnly; if (context == null) { if (NetEventSource.Log.IsEnabled()) { string protocol = isNtlmOnly ? "NTLM" : "SPNEGO"; NetEventSource.Info(context, $"requested protocol = {protocol}, target = {targetName}"); } context = new SafeDeleteNegoContext(credential, targetName !); } SafeDeleteNegoContext negoContext = (SafeDeleteNegoContext)context; try { Interop.NetSecurityNative.GssFlags inputFlags = ContextFlagsAdapterPal.GetInteropFromContextFlagsPal(inFlags, isServer: false); uint outputFlags; bool isNtlmUsed; SafeGssContextHandle?contextHandle = negoContext.GssContext; bool done = GssInitSecurityContext( ref contextHandle, credential.GssCredential, isNtlmOnly, channelBinding, negoContext.TargetName, inputFlags, incomingBlob, out resultBuffer, out outputFlags, out isNtlmUsed); if (done) { if (NetEventSource.Log.IsEnabled()) { string protocol = isNtlmOnly ? "NTLM" : isNtlmUsed ? "SPNEGO-NTLM" : "SPNEGO-Kerberos"; NetEventSource.Info(context, $"actual protocol = {protocol}"); } // Populate protocol used for authentication negoContext.SetAuthenticationPackage(isNtlmUsed); } Debug.Assert(resultBuffer != null, "Unexpected null buffer returned by GssApi"); outFlags = ContextFlagsAdapterPal.GetContextFlagsPalFromInterop( (Interop.NetSecurityNative.GssFlags)outputFlags, isServer: false); Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); // Save the inner context handle for further calls to NetSecurity Debug.Assert(negoContext.GssContext == null || contextHandle == negoContext.GssContext); if (null == negoContext.GssContext) { negoContext.SetGssContext(contextHandle !); } SecurityStatusPalErrorCode errorCode = done ? (negoContext.IsNtlmUsed && resultBuffer.Length > 0 ? SecurityStatusPalErrorCode.OK : SecurityStatusPalErrorCode.CompleteNeeded) : SecurityStatusPalErrorCode.ContinueNeeded; return(new SecurityStatusPal(errorCode)); } catch (Exception ex) { if (NetEventSource.Log.IsEnabled()) { NetEventSource.Error(null, ex); } return(new SecurityStatusPal(SecurityStatusPalErrorCode.InternalError, ex)); } }
internal NTAuthentication(bool isServer, string package, NetworkCredential credential, string?spn, ContextFlagsPal requestedContextFlags, ChannelBinding?channelBinding) { Initialize(isServer, package, credential, spn, requestedContextFlags, channelBinding); }
private static bool GssInitSecurityContext( ref SafeGssContextHandle?context, SafeGssCredHandle credential, bool isNtlm, ChannelBinding?channelBinding, SafeGssNameHandle?targetName, Interop.NetSecurityNative.GssFlags inFlags, byte[]?buffer, out byte[]?outputBuffer, out uint outFlags, out bool isNtlmUsed) { outputBuffer = null; outFlags = 0; // EstablishSecurityContext is called multiple times in a session. // In each call, we need to pass the context handle from the previous call. // For the first call, the context handle will be null. bool newContext = false; if (context == null) { newContext = true; context = new SafeGssContextHandle(); } Interop.NetSecurityNative.GssBuffer token = default(Interop.NetSecurityNative.GssBuffer); Interop.NetSecurityNative.Status status; try { Interop.NetSecurityNative.Status minorStatus; if (channelBinding != null) { // If a TLS channel binding token (cbt) is available then get the pointer // to the application specific data. int appDataOffset = Marshal.SizeOf <SecChannelBindings>(); Debug.Assert(appDataOffset < channelBinding.Size); IntPtr cbtAppData = channelBinding.DangerousGetHandle() + appDataOffset; int cbtAppDataSize = channelBinding.Size - appDataOffset; status = Interop.NetSecurityNative.InitSecContext(out minorStatus, credential, ref context, isNtlm, cbtAppData, cbtAppDataSize, targetName, (uint)inFlags, buffer, (buffer == null) ? 0 : buffer.Length, ref token, out outFlags, out isNtlmUsed); } else { status = Interop.NetSecurityNative.InitSecContext(out minorStatus, credential, ref context, isNtlm, targetName, (uint)inFlags, buffer, (buffer == null) ? 0 : buffer.Length, ref token, out outFlags, out isNtlmUsed); } if ((status != Interop.NetSecurityNative.Status.GSS_S_COMPLETE) && (status != Interop.NetSecurityNative.Status.GSS_S_CONTINUE_NEEDED)) { if (newContext) { context.Dispose(); context = null; } throw new Interop.NetSecurityNative.GssApiException(status, minorStatus); } outputBuffer = token.ToByteArray(); } finally { token.Dispose(); } return(status == Interop.NetSecurityNative.Status.GSS_S_COMPLETE); }
internal AuthenticateCallbackContext(SmtpConnection thisPtr, ISmtpAuthenticationModule module, NetworkCredential credential, string?spn, ChannelBinding?Token) { _thisPtr = thisPtr; _module = module; _credential = credential; _spn = spn; _token = Token; _result = null; }