| File: System\ServiceModel\Security\ClientCredentialsSecurityTokenManager.cs | Web Access |
| Project: src\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.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.Net; using System.Security.Authentication.ExtendedProtection; using System.Security.Principal; using System.ServiceModel.Channels; using System.ServiceModel.Description; using System.ServiceModel.Security; using System.ServiceModel.Security.Tokens; using System.Threading.Tasks; namespace System.ServiceModel { public class ClientCredentialsSecurityTokenManager : SecurityTokenManager { public ClientCredentialsSecurityTokenManager(ClientCredentials clientCredentials) { ClientCredentials = clientCredentials ?? throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(clientCredentials)); } public ClientCredentials ClientCredentials { get; } private string GetServicePrincipalName(InitiatorServiceModelSecurityTokenRequirement initiatorRequirement) { EndpointAddress targetAddress = initiatorRequirement.TargetAddress; if (targetAddress == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRP.Format(SRP.TokenRequirementDoesNotSpecifyTargetAddress, initiatorRequirement)); } IdentityVerifier identityVerifier; SecurityBindingElement securityBindingElement = initiatorRequirement.SecurityBindingElement; if (securityBindingElement != null) { identityVerifier = securityBindingElement.LocalClientSettings.IdentityVerifier; } else { identityVerifier = IdentityVerifier.CreateDefault(); } EndpointIdentity identity; identityVerifier.TryGetIdentity(targetAddress, out identity); return SecurityUtils.GetSpnFromIdentity(identity, targetAddress); } private bool IsDigestAuthenticationScheme(SecurityTokenRequirement requirement) { if (requirement.Properties.ContainsKey(ServiceModelSecurityTokenRequirement.HttpAuthenticationSchemeProperty)) { AuthenticationSchemes authScheme = (AuthenticationSchemes)requirement.Properties[ServiceModelSecurityTokenRequirement.HttpAuthenticationSchemeProperty]; if (!authScheme.IsSingleton() && authScheme != AuthenticationSchemes.IntegratedWindowsAuthentication) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument("authScheme", string.Format(SRP.HttpRequiresSingleAuthScheme, authScheme)); } return (authScheme == AuthenticationSchemes.Digest); } else { return false; } } internal protected bool IsIssuedSecurityTokenRequirement(SecurityTokenRequirement requirement) { if (requirement != null && requirement.Properties.ContainsKey(ServiceModelSecurityTokenRequirement.IssuerAddressProperty)) { // handle all issued token requirements except for spnego, tlsnego and secure conversation if (requirement.TokenType == ServiceModelSecurityTokenTypes.AnonymousSslnego || requirement.TokenType == ServiceModelSecurityTokenTypes.MutualSslnego || requirement.TokenType == ServiceModelSecurityTokenTypes.SecureConversation || requirement.TokenType == ServiceModelSecurityTokenTypes.Spnego) { return false; } else { return true; } } return false; } public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement) { if (tokenRequirement == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(tokenRequirement)); } SecurityTokenProvider result = null; if (tokenRequirement is RecipientServiceModelSecurityTokenRequirement && tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate && tokenRequirement.KeyUsage == SecurityKeyUsage.Exchange) { // this is the uncorrelated duplex case if (ClientCredentials.ClientCertificate.Certificate == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRP.Format(SRP.ClientCertificateNotProvidedOnClientCredentials))); } result = new X509SecurityTokenProvider(ClientCredentials.ClientCertificate.Certificate, ClientCredentials.ClientCertificate.CloneCertificate); } else if (tokenRequirement is InitiatorServiceModelSecurityTokenRequirement) { InitiatorServiceModelSecurityTokenRequirement initiatorRequirement = tokenRequirement as InitiatorServiceModelSecurityTokenRequirement; string tokenType = initiatorRequirement.TokenType; if (IsIssuedSecurityTokenRequirement(initiatorRequirement)) { throw ExceptionHelper.PlatformNotSupported("CreateSecurityTokenProvider (IsIssuedSecurityTokenRequirement(initiatorRequirement)"); } else if (tokenType == SecurityTokenTypes.X509Certificate) { if (initiatorRequirement.Properties.ContainsKey(SecurityTokenRequirement.KeyUsageProperty) && initiatorRequirement.KeyUsage == SecurityKeyUsage.Exchange) { throw ExceptionHelper.PlatformNotSupported("CreateSecurityTokenProvider X509Certificate - SecurityKeyUsage.Exchange"); } else { if (ClientCredentials.ClientCertificate.Certificate == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRP.Format(SRP.ClientCertificateNotProvidedOnClientCredentials))); } result = new X509SecurityTokenProvider(ClientCredentials.ClientCertificate.Certificate, ClientCredentials.ClientCertificate.CloneCertificate); } } else if (tokenType == SecurityTokenTypes.Kerberos) { string spn = GetServicePrincipalName(initiatorRequirement); result = new KerberosSecurityTokenProviderWrapper( new KerberosSecurityTokenProvider(spn, ClientCredentials.Windows.AllowedImpersonationLevel, SecurityUtils.GetNetworkCredentialOrDefault(ClientCredentials.Windows.ClientCredential))); } else if (tokenType == SecurityTokenTypes.UserName) { if (ClientCredentials.UserName.UserName == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SRP.UserNamePasswordNotProvidedOnClientCredentials)); } result = new UserNameSecurityTokenProvider(ClientCredentials.UserName.UserName, ClientCredentials.UserName.Password); } else if (tokenType == ServiceModelSecurityTokenTypes.SspiCredential) { if (IsDigestAuthenticationScheme(initiatorRequirement)) { result = new SspiSecurityTokenProvider(SecurityUtils.GetNetworkCredentialOrDefault(ClientCredentials.HttpDigest.ClientCredential), true, TokenImpersonationLevel.Delegation); } else { #pragma warning disable 618 // to disable AllowNtlm obsolete warning. result = new SspiSecurityTokenProvider(SecurityUtils.GetNetworkCredentialOrDefault(ClientCredentials.Windows.ClientCredential), ClientCredentials.Windows.AllowNtlm, ClientCredentials.Windows.AllowedImpersonationLevel); #pragma warning restore 618 } } else if (tokenType == ServiceModelSecurityTokenTypes.SecureConversation) { result = CreateSecureConversationSecurityTokenProvider(initiatorRequirement); } } if ((result == null) && !tokenRequirement.IsOptionalToken) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SRP.Format(SRP.SecurityTokenManagerCannotCreateProviderForRequirement, tokenRequirement))); } return result; } public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version) { if (version == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(version)); } MessageSecurityTokenVersion wsVersion = version as MessageSecurityTokenVersion; if (wsVersion != null) { return new WSSecurityTokenSerializer(wsVersion.SecurityVersion, wsVersion.TrustVersion, wsVersion.SecureConversationVersion, wsVersion.EmitBspRequiredAttributes, null, null, null); } else { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SRP.Format(SRP.SecurityTokenManagerCannotCreateSerializerForVersion, version))); } } private SecurityTokenProvider CreateSecureConversationSecurityTokenProvider(InitiatorServiceModelSecurityTokenRequirement initiatorRequirement) { EndpointAddress targetAddress = initiatorRequirement.TargetAddress; if (targetAddress == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRP.Format(SRP.TokenRequirementDoesNotSpecifyTargetAddress, initiatorRequirement)); } SecurityBindingElement securityBindingElement = initiatorRequirement.SecurityBindingElement; if (securityBindingElement == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgument(SRP.Format(SRP.TokenProviderRequiresSecurityBindingElement, initiatorRequirement)); } LocalClientSecuritySettings localClientSettings = securityBindingElement.LocalClientSettings; BindingContext issuerBindingContext = initiatorRequirement.GetProperty<BindingContext>(ServiceModelSecurityTokenRequirement.IssuerBindingContextProperty); ChannelParameterCollection channelParameters = initiatorRequirement.GetPropertyOrDefault<ChannelParameterCollection>(ServiceModelSecurityTokenRequirement.ChannelParametersCollectionProperty, null); bool isSessionMode = initiatorRequirement.SupportSecurityContextCancellation; if (isSessionMode) { SecuritySessionSecurityTokenProvider sessionTokenProvider = new SecuritySessionSecurityTokenProvider(); sessionTokenProvider.BootstrapSecurityBindingElement = SecurityUtils.GetIssuerSecurityBindingElement(initiatorRequirement); sessionTokenProvider.IssuedSecurityTokenParameters = initiatorRequirement.GetProperty<SecurityTokenParameters>(ServiceModelSecurityTokenRequirement.IssuedSecurityTokenParametersProperty); sessionTokenProvider.IssuerBindingContext = issuerBindingContext; sessionTokenProvider.KeyEntropyMode = securityBindingElement.KeyEntropyMode; sessionTokenProvider.SecurityAlgorithmSuite = initiatorRequirement.SecurityAlgorithmSuite; sessionTokenProvider.StandardsManager = SecurityUtils.CreateSecurityStandardsManager(initiatorRequirement, this); sessionTokenProvider.TargetAddress = targetAddress; sessionTokenProvider.Via = initiatorRequirement.GetPropertyOrDefault<Uri>(InitiatorServiceModelSecurityTokenRequirement.ViaProperty, null); Uri privacyNoticeUri; if (initiatorRequirement.TryGetProperty(ServiceModelSecurityTokenRequirement.PrivacyNoticeUriProperty, out privacyNoticeUri)) { sessionTokenProvider.PrivacyNoticeUri = privacyNoticeUri; } int privacyNoticeVersion; if (initiatorRequirement.TryGetProperty(ServiceModelSecurityTokenRequirement.PrivacyNoticeVersionProperty, out privacyNoticeVersion)) { sessionTokenProvider.PrivacyNoticeVersion = privacyNoticeVersion; } EndpointAddress localAddress; if (initiatorRequirement.TryGetProperty(ServiceModelSecurityTokenRequirement.DuplexClientLocalAddressProperty, out localAddress)) { sessionTokenProvider.LocalAddress = localAddress; } sessionTokenProvider.ChannelParameters = channelParameters; return sessionTokenProvider; } else { AcceleratedTokenProvider acceleratedTokenProvider = new AcceleratedTokenProvider(); acceleratedTokenProvider.IssuerAddress = initiatorRequirement.IssuerAddress; acceleratedTokenProvider.BootstrapSecurityBindingElement = SecurityUtils.GetIssuerSecurityBindingElement(initiatorRequirement); acceleratedTokenProvider.CacheServiceTokens = localClientSettings.CacheCookies; acceleratedTokenProvider.IssuerBindingContext = issuerBindingContext; acceleratedTokenProvider.KeyEntropyMode = securityBindingElement.KeyEntropyMode; acceleratedTokenProvider.MaxServiceTokenCachingTime = localClientSettings.MaxCookieCachingTime; acceleratedTokenProvider.SecurityAlgorithmSuite = initiatorRequirement.SecurityAlgorithmSuite; acceleratedTokenProvider.ServiceTokenValidityThresholdPercentage = localClientSettings.CookieRenewalThresholdPercentage; acceleratedTokenProvider.StandardsManager = SecurityUtils.CreateSecurityStandardsManager(initiatorRequirement, this); acceleratedTokenProvider.TargetAddress = targetAddress; acceleratedTokenProvider.Via = initiatorRequirement.GetPropertyOrDefault<Uri>(InitiatorServiceModelSecurityTokenRequirement.ViaProperty, null); return acceleratedTokenProvider; } } private X509SecurityTokenAuthenticator CreateServerX509TokenAuthenticator() { return new X509SecurityTokenAuthenticator(ClientCredentials.ServiceCertificate.Authentication.GetCertificateValidator()); } private X509SecurityTokenAuthenticator CreateServerSslX509TokenAuthenticator() { if (ClientCredentials.ServiceCertificate.SslCertificateAuthentication != null) { return new X509SecurityTokenAuthenticator(ClientCredentials.ServiceCertificate.SslCertificateAuthentication.GetCertificateValidator()); } return CreateServerX509TokenAuthenticator(); } public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver) { if (tokenRequirement == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull(nameof(tokenRequirement)); } outOfBandTokenResolver = null; SecurityTokenAuthenticator result = null; InitiatorServiceModelSecurityTokenRequirement initiatorRequirement = tokenRequirement as InitiatorServiceModelSecurityTokenRequirement; if (initiatorRequirement != null) { string tokenType = initiatorRequirement.TokenType; if (IsIssuedSecurityTokenRequirement(initiatorRequirement)) { throw ExceptionHelper.PlatformNotSupported("CreateSecurityTokenAuthenticator : GenericXmlSecurityTokenAuthenticator"); } else if (tokenType == SecurityTokenTypes.X509Certificate) { if (initiatorRequirement.IsOutOfBandToken) { // when the client side soap security asks for a token authenticator, its for doing // identity checks on the out of band server certificate result = new X509SecurityTokenAuthenticator(X509CertificateValidator.None); } else if (initiatorRequirement.PreferSslCertificateAuthenticator) { result = CreateServerSslX509TokenAuthenticator(); } else { result = CreateServerX509TokenAuthenticator(); } } else if (tokenType == SecurityTokenTypes.Rsa) { throw ExceptionHelper.PlatformNotSupported("CreateSecurityTokenAuthenticator : SecurityTokenTypes.Rsa"); } else if (tokenType == SecurityTokenTypes.Kerberos) { throw ExceptionHelper.PlatformNotSupported("CreateSecurityTokenAuthenticator : SecurityTokenTypes.Kerberos"); } else if (tokenType == ServiceModelSecurityTokenTypes.SecureConversation || tokenType == ServiceModelSecurityTokenTypes.MutualSslnego || tokenType == ServiceModelSecurityTokenTypes.AnonymousSslnego || tokenType == ServiceModelSecurityTokenTypes.Spnego) { throw ExceptionHelper.PlatformNotSupported("CreateSecurityTokenAuthenticator : GenericXmlSecurityTokenAuthenticator"); } } else if ((tokenRequirement is RecipientServiceModelSecurityTokenRequirement) && tokenRequirement.TokenType == SecurityTokenTypes.X509Certificate) { // uncorrelated duplex case result = CreateServerX509TokenAuthenticator(); } if (result == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotSupportedException(SRP.Format(SRP.SecurityTokenManagerCannotCreateAuthenticatorForRequirement, tokenRequirement))); } return result; } } internal class KerberosSecurityTokenProviderWrapper : CommunicationObjectSecurityTokenProvider { private KerberosSecurityTokenProvider _innerProvider; public KerberosSecurityTokenProviderWrapper(KerberosSecurityTokenProvider innerProvider) { _innerProvider = innerProvider; } protected override SecurityToken GetTokenCore(TimeSpan timeout) { return new KerberosRequestorSecurityToken(_innerProvider.ServicePrincipalName, _innerProvider.TokenImpersonationLevel, _innerProvider.NetworkCredential, SecurityUniqueId.Create().Value); } internal Task<SecurityToken> GetTokenAsync(TimeSpan timeout, ChannelBinding channelbinding) { return Task.FromResult(GetTokenCore(timeout)); } internal override Task<SecurityToken> GetTokenCoreInternalAsync(TimeSpan timeout) { return GetTokenAsync(timeout, null); } } }