简体   繁体   中英

How to get the X509Certificate from a client request

I have a web-service which I secured using certificates. Now, I want to identify the client by looking at the certificate thumbprint. This means that I have a list of thumbprints on my service somewhere that are linked to some user.

Actually, my first question (a little off-topic) is: is this a good approach or should I still introduce some username password construction?

Second question is: how can I get the certificate that the client used to connect to the web-service so I can read the thumbprint at the service side.

I did read a lot about it (like this post: How do I get the X509Certificate sent from the client in web service? ) but could not find an answer.

I have no HTTPContext, so that is not an option. In the post mentioned above is spoken about Context.Request.ClientCertificate.Certificate but I guess they mean the HTTPContext there as well. Also adding <serviceHostingEnvironment aspNetCompatibilityEnabled="true" /> to the web.config is also not an option.

this is how we do this in the constructor of our webservice:

if (OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets == null)
    throw new SecurityException ("No claimset service configured wrong");

if (OperationContext.Current.ServiceSecurityContext.AuthorizationContext.ClaimSets.Count <= 0)
    throw new SecurityException ("No claimset service configured wrong");


var cert = ((X509CertificateClaimSet) OperationContext.Current.ServiceSecurityContext.
            AuthorizationContext.ClaimSets[0]).X509Certificate;

//this contains the thumbprint
cert.Thumbprint

I don't think there is anything wrong with this approach, as long as this service is used in an environment where you can control certificate distribution and ensure they are stored securely.

Assuming this is a WCF service, you can get the certificate the client is presenting using a class that inherits from ServiceAuthorizationManager . Something like this will do the job:

public class CertificateAuthorizationManager : ServiceAuthorizationManager
{
    protected override bool CheckAccessCore(OperationContext operationContext)
    {
        if (!base.CheckAccessCore(operationContext))
        {
            return false;
        }

        string thumbprint = GetCertificateThumbprint(operationContext);

        // TODO: Check the thumbprint against your database, then return true if found, otherwise false
    }

    private string GetCertificateThumbprint(OperationContext operationContext)
    {
        foreach (var claimSet in operationContext.ServiceSecurityContext.AuthorizationContext.ClaimSets)
        {
            foreach (Claim claim in claimSet.FindClaims(ClaimTypes.Thumbprint, Rights.Identity))
            {
                string tb = BitConverter.ToString((byte[])claim.Resource);
                tb = tb.Replace("-", "");
                return tb;
            }
        }

        throw new System.Security.SecurityException("No client certificate found");
    }
}

You then need to change your configuration at the server to use this authorization manager:

<system.serviceModel>

    <behaviors>
        <serviceBehaviors>
            <behavior name="MyServerBehavior">

                <serviceAuthorization serviceAuthorizationManagerType="myNamespace.CertificateAuthorizationManager, myAssembly"/>

                ...

            </behavior>
        </serviceBehaviors>
    </behaviors>

    ...

</system.serviceModel>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM