Как получить сертификат X509 от запроса клиента
У меня есть веб-сервис, который я получил с помощью сертификатов.
Теперь я хочу идентифицировать клиента, посмотрев на отпечаток сертификата. Это означает, что у меня есть список отпечатков на моей службе где-то, которые связаны с некоторым пользователем.
На самом деле, мой первый вопрос (немного не по теме): это хороший подход или мне еще нужно ввести некоторую конструкцию паролей имени пользователя?
Второй вопрос: как я могу получить сертификат, который клиент использовал для подключения к веб-сервису, чтобы я мог прочитать отпечаток на стороне службы.
Я много читал об этом (например, этот пост: Как мне получить сертификат X509, отправленный клиентом в веб-службе?), но не смог найти ответ.
У меня нет HTTPContext, так что это не вариант. В упомянутом выше сообщении говорится о Context.Request.ClientCertificate.Certificate
, но я думаю, что они также означают HTTPContext
. Кроме того, добавление <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />
в web.config также не является вариантом.
Ответы
Ответ 1
так мы делаем это в конструкторе нашего веб-сервиса:
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
Ответ 2
Я не думаю, что с этим подходом что-то не так, пока эта служба используется в среде, где вы можете контролировать распределение сертификатов и обеспечить их надежную защиту.
Предполагая, что это служба WCF, вы можете получить сертификат, который клиент представляет, используя класс, который наследует от ServiceAuthorizationManager
. Что-то вроде этого выполнит работу:
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");
}
}
Затем вам нужно изменить конфигурацию на сервере, чтобы использовать этот диспетчер авторизации:
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="MyServerBehavior">
<serviceAuthorization serviceAuthorizationManagerType="myNamespace.CertificateAuthorizationManager, myAssembly"/>
...
</behavior>
</serviceBehaviors>
</behaviors>
...
</system.serviceModel>