问题
Hello,
I am trying to use WCF to do some authentication:
- Authenticate the user using Username/Passoword
- Authenticate the client using a client certificate
- Customize which root certificate are accepted
After some trial and error, i managed to get points 1 & 2 working, but i am stuck on 3. This is my service configuration
<system.serviceModel>
<behaviors>
<endpointBehaviors />
<serviceBehaviors>
<behavior name="MyBehavior">
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="Custom"
customUserNamePasswordValidatorType="WcfService1.CustomValidator, WcfService1" />
</serviceCredentials>
<serviceMetadata httpsGetEnabled="true" httpGetEnabled="false" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<customBinding>
<binding name="certificate">
<security authenticationMode="UserNameOverTransport" />
<textMessageEncoding messageVersion="Soap12WSAddressing10" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
</bindings>
<services>
<service behaviorConfiguration="MyBehavior" name="WcfService1.Service1">
<endpoint address="" binding="customBinding" bindingConfiguration="certificate"
contract="WcfService1.IService1" />
</service>
</services>
</system.serviceModel>
and this is my client configuration
<client>
<endpoint name="service1" address="https://localhost:443/WcfService1/Service1.svc" binding="customBinding"
bindingConfiguration="certificate" behaviorConfiguration="certificate" contract="WcfService1.IService1" />
</client>
<behaviors>
<endpointBehaviors>
<behavior name="certificate">
<clientCredentials>
<clientCertificate storeName="My" storeLocation="LocalMachine" x509FindType="FindBySubjectName"
findValue="SignedByCA" />
</clientCredentials>
</behavior>
</endpointBehaviors>
<serviceBehaviors />
</behaviors>
<bindings>
<customBinding>
<binding name="certificate">
<security authenticationMode="UserNameOverTransport" />
<textMessageEncoding messageVersion="Soap12WSAddressing10" />
<httpsTransport requireClientCertificate="true" />
</binding>
</customBinding>
</bindings>
Using the client and attaching username credentials works nicely
var channelFactory = new ChannelFactory<IService1>("service1");
var user = channelFactory.Credentials.UserName;
user.UserName = username;
user.Password = password;
Using OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets gives me access to the username and the name and thumbprint of the certificate. Sadly, i am unable to find the IssuerName of the certificate. How else can I disallow clients that do not have a certificate issued by a certain root certificate?
Any hints to point me into the right direction or any alternatives are greatly welcome ;)
Thanks
回答1:
Actually, it's easy, but a hack. There is a list of identities in the authorization context.
OperationContext.Current.ServiceSecurityContext
.AuthorizationContext.Properties["Identities"]
One of which is of type X509Identity. That one is internal to System.IdentityModel, you you can't get it directly.
identity.GetType().Name == "X509Identity"
It doesn't really matter, because the field containing the certificate is private, anyways :)
var field = identity.GetType().GetField(
"certificate",
BindingFlags.GetField | BindingFlags.Instance | BindingFlags.NonPublic);
var certificate = (X509Certificate2) field.GetValue(identity);
string issuer = certificate.Issuer;
来源:https://stackoverflow.com/questions/11966576/custom-wcf-client-certificate-over-ssl-validation