Custom WCF client certificate over ssl validation

旧时模样 提交于 2020-01-06 15:41:30

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!