| File: System\ServiceModel\Security\SpnegoTokenProvider.cs | Web Access |
| Project: ..\..\..\src\System.ServiceModel.Primitives\src\System.ServiceModel.Primitives.csproj (System.ServiceModel.Primitives) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using System.Collections.ObjectModel; using System.Globalization; using System.IdentityModel.Claims; using System.IdentityModel.Policy; using System.Net; using System.Security.Principal; using System.ServiceModel.Channels; using System.Threading.Tasks; using System.Xml; using static System.ServiceModel.Security.SecurityUtils; namespace System.ServiceModel.Security { internal class SpnegoTokenProvider : SspiNegotiationTokenProvider { private TokenImpersonationLevel _allowedImpersonationLevel = TokenImpersonationLevel.Identification; private ICredentials _clientCredential; private IdentityVerifier _identityVerifier = IdentityVerifier.CreateDefault(); //private bool _allowNtlm = true; private bool _authenticateServer = true; private NetworkCredential _networkCredential; public SpnegoTokenProvider(NetworkCredential networkCredential, SecurityBindingElement securityBindingElement) : base(securityBindingElement) { _networkCredential = networkCredential; } // settings public IdentityVerifier IdentityVerifier { get { return _identityVerifier; } set { CommunicationObject.ThrowIfDisposedOrImmutable(); _identityVerifier = value; } } public TokenImpersonationLevel AllowedImpersonationLevel { get { return _allowedImpersonationLevel; } set { CommunicationObject.ThrowIfDisposedOrImmutable(); TokenImpersonationLevelHelper.Validate(value); if (value == TokenImpersonationLevel.None) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new ArgumentOutOfRangeException(nameof(value), string.Format(CultureInfo.InvariantCulture, SRP.SpnegoImpersonationLevelCannotBeSetToNone))); } _allowedImpersonationLevel = value; } } public ICredentials ClientCredential { get { return _clientCredential; } set { CommunicationObject.ThrowIfDisposedOrImmutable(); _clientCredential = value; } } public bool AuthenticateServer { get { return _authenticateServer; } set { CommunicationObject.ThrowIfDisposedOrImmutable(); _authenticateServer = value; } } // overrides public override XmlDictionaryString NegotiationValueType { get { return XD.TrustApr2004Dictionary.SpnegoValueTypeUri; } } public override void OnOpening() { base.OnOpening(); if (_networkCredential == null) { string packageName = "Negotiate"; NetworkCredential credential = null; if (_clientCredential != null) { credential = _clientCredential.GetCredential(TargetAddress.Uri, packageName); } if (credential == null) { credential = CredentialCache.DefaultNetworkCredentials; } else if (!NetworkCredentialHelper.IsDefault(credential)) { SecurityUtils.FixNetworkCredential(ref credential); } _networkCredential = credential; } } public override async Task OnCloseAsync(TimeSpan timeout) { await base.OnCloseAsync(timeout); FreeCredentialsHandle(); } public override void OnAbort() { base.OnAbort(); FreeCredentialsHandle(); } void FreeCredentialsHandle() { _networkCredential = null; } protected override Task<SspiNegotiationTokenProviderState> CreateNegotiationStateAsync(EndpointAddress target, Uri via, TimeSpan timeout) { return Task.FromResult(CreateNegotiationState(target, via, timeout)); } private SspiNegotiationTokenProviderState CreateNegotiationState(EndpointAddress target, Uri via, TimeSpan timeout) { EnsureEndpointAddressDoesNotRequireEncryption(target); EndpointIdentity identity = null; if (_identityVerifier == null) { identity = target.Identity; } else { _identityVerifier.TryGetIdentity(target, out identity); } string spn; if (AuthenticateServer) { spn = SecurityUtils.GetSpnFromIdentity(identity, target); } else { // if an SPN or UPN identity is configured (for example, in mixed mode SSPI), then // use that identity for Negotiate Claim identityClaim = identity?.IdentityClaim; if (identityClaim != null && (identityClaim.ClaimType == ClaimTypes.Spn || identityClaim.ClaimType == ClaimTypes.Upn)) { spn = identityClaim.Resource.ToString(); } else { spn = "host/" + target.Uri.DnsSafeHost; } } string packageName = "Negotiate"; NetworkCredential credential = null; if (_clientCredential != null) { credential = _clientCredential.GetCredential(target.Uri, packageName); } WindowsSspiNegotiation sspiNegotiation = new WindowsSspiNegotiation( packageName, credential, AllowedImpersonationLevel, spn, true); return new SspiNegotiationTokenProviderState(sspiNegotiation); } protected override ReadOnlyCollection<IAuthorizationPolicy> ValidateSspiNegotiation(ISspiNegotiation sspiNegotiation) { WindowsSspiNegotiation windowsNegotiation = (WindowsSspiNegotiation)sspiNegotiation; if (windowsNegotiation.IsValidContext == false) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SRP.InvalidSspiNegotiation)); } if (AuthenticateServer && windowsNegotiation.IsMutualAuthFlag == false) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new SecurityNegotiationException(SRP.CannotAuthenticateServer)); } return SecurityUtils.CreatePrincipalNameAuthorizationPolicies(windowsNegotiation.ServicePrincipalName); } } }