방법: 사용자 지정 인증서 유효성 검사기를 사용하는 서비스 만들기
이 항목에서는 사용자 지정 인증서 유효성 검사기를 구현하는 방법과 클라이언트 또는 서비스 자격 증명을 구성하여 기본 인증서 유효성 검사 논리를 사용자 지정 인증서 유효성 검사기로 바꾸는 방법을 보여 줍니다.
X.509 인증서를 사용하여 클라이언트 또는 서비스를 인증하는 경우 WCF(Windows Communication Foundation)는 기본적으로 Windows 인증서 저장소와 Crypto API를 사용하여 인증서의 유효성을 검사하고 신뢰할 수 있는지 유효성을 검사합니다. 기본 제공 인증서 유효성 검사 기능으로 충분하지 않은 경우에는 변경해야 합니다. WCF에서는 사용자가 사용자 지정 인증서 유효성 검사기를 추가할 수 있도록 하여 쉽게 유효성 검사 논리를 변경하는 방법을 제공합니다. 사용자 지정 인증서 유효성 검사기를 지정하면 WCF에서 기본 제공 인증서 유효성 검사 논리를 사용하지 않고 대신 사용자 지정 유효성 검사기를 사용합니다.
절차
사용자 지정 인증서 유효성 검사기를 만들려면
X509CertificateValidator에서 파생된 새 클래스를 정의합니다.
추상 Validate 메서드를 구현합니다. 유효성을 검사해야 하는 인증서는 인수로 메서드에 전달됩니다. 전달된 인증서가 유효성 검사 논리에 따라 유효하지 않은 경우 이 메서드는 SecurityTokenValidationException을 throw합니다. 인증서가 유효하면 메서드가 호출자에게 반환됩니다.
참고 항목
인증 오류를 다시 클라이언트에 반환하려면 FaultException 메서드에서 Validate을 throw합니다.
public class MyX509CertificateValidator : X509CertificateValidator
{
string allowedIssuerName;
public MyX509CertificateValidator(string allowedIssuerName)
{
if (allowedIssuerName == null)
{
throw new ArgumentNullException("allowedIssuerName");
}
this.allowedIssuerName = allowedIssuerName;
}
public override void Validate(X509Certificate2 certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
// Check that the certificate issuer matches the configured issuer.
if (allowedIssuerName != certificate.IssuerName.Name)
{
throw new SecurityTokenValidationException
("Certificate was not issued by a trusted issuer");
}
}
}
Public Class MyX509CertificateValidator
Inherits X509CertificateValidator
Private allowedIssuerName As String
Public Sub New(ByVal allowedIssuerName As String)
If allowedIssuerName Is Nothing Then
Throw New ArgumentNullException("allowedIssuerName")
End If
Me.allowedIssuerName = allowedIssuerName
End Sub
Public Overrides Sub Validate(ByVal certificate As X509Certificate2)
' Check that there is a certificate.
If certificate Is Nothing Then
Throw New ArgumentNullException("certificate")
End If
' Check that the certificate issuer matches the configured issuer.
If allowedIssuerName <> certificate.IssuerName.Name Then
Throw New SecurityTokenValidationException _
("Certificate was not issued by a trusted issuer")
End If
End Sub
End Class
서비스 구성에 사용자 지정 인증서 유효성 검사기를 지정하려면
<behaviors> 요소와 <serviceBehaviors>를 <system.serviceModel> 요소에 추가합니다.
<behavior>를 추가하고
name
특성을 적절한 값으로 설정합니다.<behavior>
요소에 <serviceCredentials>를 추가합니다.<clientCertificate>
요소를<serviceCredentials>
요소에 추가합니다.<clientCertificate>
요소에 <authentication>을 추가합니다.customCertificateValidatorType
특성을 유효성 검사기 형식으로 설정합니다. 다음 예제에서는 특성을 형식의 네임스페이스 및 이름으로 설정합니다.certificateValidationMode
특성을Custom
으로 설정합니다.<configuration> <system.serviceModel> <behaviors> <serviceBehaviors> <behavior name="ServiceBehavior"> <serviceCredentials> <clientCertificate> <authentication certificateValidationMode="Custom" customCertificateValidatorType="Samples.MyValidator, service" /> </clientCertificate> </serviceCredentials> </behavior> </serviceBehaviors> </behaviors> </system.serviceModel> </configuration>
클라이언트에 구성을 사용하여 사용자 지정 인증서 유효성 검사기를 지정하려면
<behaviors> 요소와 <serviceBehaviors>를 <system.serviceModel> 요소에 추가합니다.
<endpointBehaviors> 요소를 추가합니다.
<behavior>
요소를 추가하고name
특성을 적절한 값으로 설정합니다.<clientCredentials> 요소를 추가합니다.
<serviceCertificate>를 추가합니다.
다음 예와 같이 <authentication>을 추가합니다.
customCertificateValidatorType
특성을 유효성 검사기 형식으로 설정합니다.certificateValidationMode
특성을Custom
으로 설정합니다. 다음 예제에서는 특성을 형식의 네임스페이스 및 이름으로 설정합니다.<configuration> <system.serviceModel> <behaviors> <endpointBehaviors> <behavior name="clientBehavior"> <clientCredentials> <serviceCertificate> <authentication certificateValidationMode="Custom" customCertificateValidatorType= "Samples.CustomX509CertificateValidator, client"/> </serviceCertificate> </clientCredentials> </behavior> </endpointBehaviors> </behaviors> </system.serviceModel> </configuration>
서비스에 코드를 사용하여 사용자 지정 인증서 유효성 검사기를 지정하려면
ClientCertificate 속성에 사용자 지정 인증서 유효성 검사기를 지정합니다. Credentials 속성을 사용하여 서비스 자격 증명에 액세스할 수 있습니다.
CertificateValidationMode 속성을 Custom로 설정합니다.
serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator =
new MyX509CertificateValidator("CN=Contoso.com");
serviceHost.Credentials.ClientCertificate.Authentication. _
CertificateValidationMode = X509CertificateValidationMode.Custom
serviceHost.Credentials.ClientCertificate.Authentication. _
CustomCertificateValidator = New MyX509CertificateValidator("CN=Contoso.com")
클라이언트에 코드를 사용하여 사용자 지정 인증서 유효성 검사기를 지정하려면
CustomCertificateValidator 속성을 사용하여 사용자 지정 인증서 유효성 검사기를 지정합니다. Credentials 속성을 사용하여 클라이언트 자격 증명에 액세스할 수 있습니다. (ServiceModel 메타데이터 유틸리티 도구(Svcutil.exe)에 의해 생성된 클라이언트 클래스는 항상 ClientBase<TChannel> 클래스에서 파생됩니다.)
CertificateValidationMode 속성을 Custom로 설정합니다.
예제
설명
다음 샘플에서는 서비스에 사용자 지정 인증서 유효성 검사기를 구현하고 사용하는 방법을 보여 줍니다.
코드
using System;
using System.IdentityModel.Selectors;
using System.IdentityModel.Tokens;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
using System.ServiceModel.Security;
namespace Microsoft.ServiceModel.Samples
{
[ServiceContract(Namespace="http://Microsoft.ServiceModel.Samples")]
public interface ICalculator
{
[OperationContract]
double Add(double n1, double n2);
}
public class CalculatorService : ICalculator
{
public double Add(double n1, double n2)
{
double result = n1 + n2;
return result;
}
}
class Program
{
static void Main()
{
using (ServiceHost serviceHost = new ServiceHost(typeof(CalculatorService)))
{
serviceHost.Credentials.ClientCertificate.Authentication.CertificateValidationMode =
X509CertificateValidationMode.Custom;
serviceHost.Credentials.ClientCertificate.Authentication.CustomCertificateValidator =
new MyX509CertificateValidator("CN=Contoso.com");
serviceHost.Open();
Console.WriteLine("Service started, press ENTER to stop ...");
Console.ReadLine();
serviceHost.Close();
}
}
}
public class MyX509CertificateValidator : X509CertificateValidator
{
string allowedIssuerName;
public MyX509CertificateValidator(string allowedIssuerName)
{
if (allowedIssuerName == null)
{
throw new ArgumentNullException("allowedIssuerName");
}
this.allowedIssuerName = allowedIssuerName;
}
public override void Validate(X509Certificate2 certificate)
{
// Check that there is a certificate.
if (certificate == null)
{
throw new ArgumentNullException("certificate");
}
// Check that the certificate issuer matches the configured issuer.
if (allowedIssuerName != certificate.IssuerName.Name)
{
throw new SecurityTokenValidationException
("Certificate was not issued by a trusted issuer");
}
}
}
}
Imports System.IdentityModel.Selectors
Imports System.Security.Cryptography.X509Certificates
Imports System.ServiceModel
Imports System.ServiceModel.Security
Imports System.IdentityModel.Tokens
Imports System.Security.Permissions
<ServiceContract([Namespace]:="http://Microsoft.ServiceModel.Samples")> _
Public Interface ICalculator
<OperationContract()> _
Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double
End Interface
Public Class CalculatorService
Implements ICalculator
Public Function Add(ByVal n1 As Double, ByVal n2 As Double) As Double _
Implements ICalculator.Add
Dim result As Double = n1 + n2
Return result
End Function
End Class
Class Program
Shared Sub Main()
Dim serviceHost As New ServiceHost(GetType(CalculatorService))
Try
serviceHost.Credentials.ClientCertificate.Authentication. _
CertificateValidationMode = X509CertificateValidationMode.Custom
serviceHost.Credentials.ClientCertificate.Authentication. _
CustomCertificateValidator = New MyX509CertificateValidator("CN=Contoso.com")
serviceHost.Open()
Console.WriteLine("Service started, press ENTER to stop ...")
Console.ReadLine()
serviceHost.Close()
Finally
serviceHost.Close()
End Try
End Sub
End Class
Public Class MyX509CertificateValidator
Inherits X509CertificateValidator
Private allowedIssuerName As String
Public Sub New(ByVal allowedIssuerName As String)
If allowedIssuerName Is Nothing Then
Throw New ArgumentNullException("allowedIssuerName")
End If
Me.allowedIssuerName = allowedIssuerName
End Sub
Public Overrides Sub Validate(ByVal certificate As X509Certificate2)
' Check that there is a certificate.
If certificate Is Nothing Then
Throw New ArgumentNullException("certificate")
End If
' Check that the certificate issuer matches the configured issuer.
If allowedIssuerName <> certificate.IssuerName.Name Then
Throw New SecurityTokenValidationException _
("Certificate was not issued by a trusted issuer")
End If
End Sub
End Class