//----------------------------------------------------------------------------- // Copyright (c) Microsoft Corporation. All rights reserved. //----------------------------------------------------------------------------- namespace System.ServiceModel.Description { using System.Collections.Generic; using System.Collections.ObjectModel; using System.IdentityModel.Configuration; using System.IdentityModel.Selectors; using System.IdentityModel.Tokens; using System.Security.Claims; using System.Security.Cryptography.X509Certificates; using System.ServiceModel.Channels; using System.ServiceModel.Security; using System.ServiceModel.Security.Tokens; using System.ServiceModel.Dispatcher; public class ServiceCredentials : SecurityCredentialsManager, IServiceBehavior { UserNamePasswordServiceCredential userName; X509CertificateInitiatorServiceCredential clientCertificate; X509CertificateRecipientServiceCredential serviceCertificate; WindowsServiceCredential windows; IssuedTokenServiceCredential issuedToken; PeerCredential peer; SecureConversationServiceCredential secureConversation; bool useIdentityConfiguration = false; bool isReadOnly = false; bool saveBootstrapTokenInSession = true; IdentityConfiguration identityConfiguration; ExceptionMapper exceptionMapper; public ServiceCredentials() { this.userName = new UserNamePasswordServiceCredential(); this.clientCertificate = new X509CertificateInitiatorServiceCredential(); this.serviceCertificate = new X509CertificateRecipientServiceCredential(); this.windows = new WindowsServiceCredential(); this.issuedToken = new IssuedTokenServiceCredential(); this.peer = new PeerCredential(); this.secureConversation = new SecureConversationServiceCredential(); this.exceptionMapper = new ExceptionMapper(); this.UseIdentityConfiguration = false; } protected ServiceCredentials(ServiceCredentials other) { if (other == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("other"); } this.userName = new UserNamePasswordServiceCredential(other.userName); this.clientCertificate = new X509CertificateInitiatorServiceCredential(other.clientCertificate); this.serviceCertificate = new X509CertificateRecipientServiceCredential(other.serviceCertificate); this.windows = new WindowsServiceCredential(other.windows); this.issuedToken = new IssuedTokenServiceCredential(other.issuedToken); this.peer = new PeerCredential(other.peer); this.secureConversation = new SecureConversationServiceCredential(other.secureConversation); this.identityConfiguration = other.identityConfiguration; this.saveBootstrapTokenInSession = other.saveBootstrapTokenInSession; this.exceptionMapper = other.exceptionMapper; this.UseIdentityConfiguration = other.useIdentityConfiguration; } public UserNamePasswordServiceCredential UserNameAuthentication { get { return this.userName; } } public X509CertificateInitiatorServiceCredential ClientCertificate { get { return this.clientCertificate; } } public X509CertificateRecipientServiceCredential ServiceCertificate { get { return this.serviceCertificate; } } public WindowsServiceCredential WindowsAuthentication { get { return this.windows; } } public IssuedTokenServiceCredential IssuedTokenAuthentication { get { return this.issuedToken; } } public PeerCredential Peer { get { return this.peer; } } public SecureConversationServiceCredential SecureConversationAuthentication { get { return this.secureConversation; } } /// /// Gets or sets the ExceptionMapper to be used when throwing exceptions. /// public ExceptionMapper ExceptionMapper { get { return this.exceptionMapper; } set { ThrowIfImmutable(); if (value == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("value"); } this.exceptionMapper = value; } } public IdentityConfiguration IdentityConfiguration { get { return this.identityConfiguration; } set { ThrowIfImmutable(); this.identityConfiguration = value; } } public bool UseIdentityConfiguration { get { return this.useIdentityConfiguration; } set { ThrowIfImmutable(); this.useIdentityConfiguration = value; if (this.identityConfiguration == null && this.useIdentityConfiguration) { this.identityConfiguration = new IdentityConfiguration(); } } } internal static ServiceCredentials CreateDefaultCredentials() { return new ServiceCredentials(); } public override SecurityTokenManager CreateSecurityTokenManager() { if (this.useIdentityConfiguration) { // // Note: the token manager we create here is always a wrapper over the default collection of token handlers // return new FederatedSecurityTokenManager(this.Clone()); } else { return new ServiceCredentialsSecurityTokenManager(this.Clone()); } } protected virtual ServiceCredentials CloneCore() { return new ServiceCredentials(this); } public ServiceCredentials Clone() { ServiceCredentials result = CloneCore(); if (result == null || result.GetType() != this.GetType()) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new NotImplementedException(SR.GetString(SR.CloneNotImplementedCorrectly, this.GetType(), (result != null) ? result.ToString() : "null"))); } return result; } void IServiceBehavior.Validate(ServiceDescription description, ServiceHostBase serviceHostBase) { // // Only pass a name if there was a name explicitly given to this class, otherwise ServiceConfig will require // a config section with the default configuration. // if (this.UseIdentityConfiguration) { ConfigureServiceHost(serviceHostBase); } } /// /// Helper method that Initializes the SecurityTokenManager used by the ServiceHost. /// By default the method sets the SecurityTokenHandlers initialized with IdentityConfiguration on the ServiceHost. /// /// ServiceHost instance to configure with FederatedSecurityTokenManager. /// One of the input argument is null. void ConfigureServiceHost(ServiceHostBase serviceHost) { if (serviceHost == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("serviceHost"); } // Throw if the serviceHost is in a bad state to do the configuration if (!(serviceHost.State == CommunicationState.Created || serviceHost.State == CommunicationState.Opening)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperInvalidOperation(SR.GetString(SR.ID4041, serviceHost)); } #pragma warning suppress 56506 if (this.ServiceCertificate != null) { X509Certificate2 serverCert = this.ServiceCertificate.Certificate; if (serverCert != null) { this.IdentityConfiguration.ServiceCertificate = serverCert; } } if (this.IssuedTokenAuthentication != null && this.IssuedTokenAuthentication.KnownCertificates != null && this.IssuedTokenAuthentication.KnownCertificates.Count > 0) { this.IdentityConfiguration.KnownIssuerCertificates = new List (this.IssuedTokenAuthentication.KnownCertificates); } // // Initialize the service configuration // if (!this.IdentityConfiguration.IsInitialized) { this.IdentityConfiguration.Initialize(); } // #pragma warning suppress 56506 // serviceHost.Authorization is never null. if (serviceHost.Authorization.ServiceAuthorizationManager == null) { serviceHost.Authorization.ServiceAuthorizationManager = new IdentityModelServiceAuthorizationManager(); } else if (!(serviceHost.Authorization.ServiceAuthorizationManager is IdentityModelServiceAuthorizationManager)) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ID4039))); } // If SecuritySessionTokenHandler is being used then null the WCF SecurityStateEncoder. if ((this.IdentityConfiguration.SecurityTokenHandlers[typeof(SecurityContextSecurityToken)] != null) && (serviceHost.Credentials.SecureConversationAuthentication.SecurityStateEncoder == null)) { serviceHost.Credentials.SecureConversationAuthentication.SecurityStateEncoder = new NoOpSecurityStateEncoder(); } } void IServiceBehavior.AddBindingParameters(ServiceDescription description, ServiceHostBase serviceHostBase, Collection endpoints, BindingParameterCollection parameters) { if (parameters == null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperArgumentNull("parameters"); } // throw if bindingParameters already has a SecurityCredentialsManager SecurityCredentialsManager otherCredentialsManager = parameters.Find(); if (otherCredentialsManager != null) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.MultipleSecurityCredentialsManagersInServiceBindingParameters, otherCredentialsManager))); } parameters.Add(this); } void IServiceBehavior.ApplyDispatchBehavior(ServiceDescription description, ServiceHostBase serviceHostBase) { for (int i = 0; i < serviceHostBase.ChannelDispatchers.Count; i++) { ChannelDispatcher channelDispatcher = serviceHostBase.ChannelDispatchers[i] as ChannelDispatcher; if (channelDispatcher != null && !ServiceMetadataBehavior.IsHttpGetMetadataDispatcher(description, channelDispatcher)) { foreach (EndpointDispatcher endpointDispatcher in channelDispatcher.Endpoints) { DispatchRuntime behavior = endpointDispatcher.DispatchRuntime; behavior.RequireClaimsPrincipalOnOperationContext = this.useIdentityConfiguration; } } } } internal void MakeReadOnly() { this.isReadOnly = true; this.ClientCertificate.MakeReadOnly(); this.IssuedTokenAuthentication.MakeReadOnly(); this.Peer.MakeReadOnly(); this.SecureConversationAuthentication.MakeReadOnly(); this.ServiceCertificate.MakeReadOnly(); this.UserNameAuthentication.MakeReadOnly(); this.WindowsAuthentication.MakeReadOnly(); } void ThrowIfImmutable() { if (this.isReadOnly) { throw DiagnosticUtility.ExceptionUtility.ThrowHelperError(new InvalidOperationException(SR.GetString(SR.ObjectIsReadOnly))); } } } }