I just stumbled upon this question unanswered many months later, and finally I can answer it. I went with a solution very similar to the ASP.NET website + Windows Forms application + WCF service: client credentials . Nevertheless, I decided that I would write my approach here.
( ) WCF /, - , . , - X509, WCF . , , ChannelFactory ASP.NET, , WCF, .
ServiceHost, URL- . - TransportWithMessageCredential, - , - .
var usernameBinding = new BasicHttpBinding( BasicHttpSecurityMode.TransportWithMessageCredential )
usernameBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.UserName;
var certificateBinding = new BasicHttpBinding( BasicHttpSecurityMode.TransportWithMessageCredential )
certificateBinding.Security.Message.ClientCredentialType = BasicHttpMessageCredentialType.Certificate;
var serviceHost = new ServiceHost( new MyService() );
serviceHost.Description.Namespace = "http://schemas.mycompany.com/MyProject";
serviceHost.AddServiceEndpoint( typeof( T ), usernameBinding, "https://myserver/MyProject/MyService" );
serviceHost.AddServiceEndpoint( typeof( T ), certificateBinding, "https://myserver/MyProject/Web/MyService" );
ServiceCredentials : ) , ) ) . , WCF (A + B + C), A + B, A + C.
var serviceCredentials = new ServiceCredentials();
serviceCredentials.ServiceCertificate.SetCertificate( StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "myserver" );
serviceCredentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
serviceCredentials.UserNameAuthentication.CustomUserNamePasswordValidator = this.UserNamePasswordValidator;
serviceCredentials.ClientCertificate.Authentication.CertificateValidationMode = X509CertificateValidationMode.None;
serviceCredentials.ClientCertificate.SetCertificate( StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "SelfSignedWebsiteCertificate" );
serviceHost.Description.Behaviors.Add( serviceCredentials );
, IAuthorizationPolicy ServiceHost ServiceAuthorizationBehavior. , UserNamePasswordValidator, , IPrincipal , . X509, , , , , . IAuthorzationPolicy.Evaluate:
public bool Evaluate( EvaluationContext evaluationContext, ref object state )
{
var identity = ((List<IIdentity>) evaluationContext.Properties[ "Identities" ] ).First();
if ( identity.AuthenticationType == "MyCustomUserNamePasswordValidator" )
{
evaluationContext.Properties[ "Principal" ] = new GenericPrincipal( identity, null );
}
else if ( identity.AuthenticationType == "X509" )
{
var impersonatedUsername = OperationContext.Current.IncomingMessageHeaders.GetHeader<string>( "ImpersonatedUsername", "http://schemas.mycompany.com/MyProject" );
evaluationContext.AddClaimSet( this, new DefaultClaimSet( Claim.CreateNameClaim( impersonatedUsername ) ) );
var impersonatedIdentity = new GenericIdentity( impersonatedUsername, "ImpersonatedUsername" );
evaluationContext.Properties[ "Identities" ] = new List<IIdentity>() { impersonatedIdentity };
evaluationContext.Properties[ "Principal" ] = new GenericPrincipal( identity, null );
}
else
throw new Exception( "Bad identity" );
return true;
}
ServiceHost :
serviceHost.Authorization.ExternalAuthorizationPolicies = new List<IAuthorizationPolicy>() { new CustomAuthorizationPolicy() }.AsReadOnly();
serviceHost.Authorization.PrincipalPermissionMode = PrincipalPermissionMode.Custom;
ServiceSecurityContext.Current.PrimaryIdentity , , . WCF. ASP.NET (certificateBinding, ), ChannelFactory. factory.Endpoint.Behaviors, HttpContext.Current.User WCF, . , IClientMessageInspector BeforeSendRequest, ( ):
public object BeforeSendRequest( ref System.ServiceModel.Channels.Message request, System.ServiceModel.IClientChannel channel )
{
request.Headers.Add( MessageHeader.CreateHeader( "ImpersonatedUsername", "http://schemas.mycompany.com/MyProject", HttpContext.Current.User.Identity.Name ) );
return null;
}
, IEndpointBehavior, . , ; :
public class GenericClientInspectorBehavior : IEndpointBehavior
{
public IClientMessageInspector Inspector { get; private set; }
public GenericClientInspectorBehavior( IClientMessageInspector inspector )
{ Inspector = inspector; }
public void ApplyClientBehavior( ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime )
{ clientRuntime.MessageInspectors.Add( Inspector ); }
}
, , , ChannelFactory :
factory.Credentials.ClientCertificate.SetCertificate( StoreLocation.LocalMachine, StoreName.My, X509FindType.FindBySubjectName, "SelfSignedWebsiteCertificate" );
factory.Endpoint.Behaviors.Add( new GenericClientInspectorBehavior( new HttpContextAuthenticationInspector() ) );
- , HttpContext.Current.User, . -, ChannelFactory, , / ClientCredentials WCF. , , .
FormsAuthentication IPrincipal HttpContext.Current.User. ChannelFactory, _, ChannelFactory, certificateBinding, ASP.NET. ChannelFactory HttpContext.Current.User WCF.
, ChannelFactory WCF ASP.NET, ChannelFactory , . , , .