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>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With