Geneva Framework

사용자 지정 보안 토큰 서비스 구축

Michele Leroux Bustamante

이 기사는 "Geneva" Framework의 시험판 버전을 기준으로 합니다. 모든 정보는 변경될 수 있습니다.

이 기사에서는 다음 내용에 대해 설명합니다.

  • Geneva Framework로 보안 토큰 서비스 구현
  • 페더레이션된 보안
  • 클레임 변환
이 기사에서 사용하는 기술:
Windows Communication Foundation, ASP.NET, Geneva Framework

코드는 MSDN 코드 갤러리에서 다운로드할 수 있습니다.
온라인으로 코드 찾아보기

목차

보안 토큰 서비스 입문
사용자 지정 액티브 STS 작성
SecurityTokenService 확장
STS 호스트 및 구성
보안 토큰 처리기
사용자 지정 패시브 STS 작성
FederatedPassiveTokenService 컨트롤
SessionAuthenticationModule
사용자 인증
클레임 변환
요약

Microsoft CBA(클레임 기반 액세스) 플랫폼 전략(코드 이름 "Geneva")에는 "Geneva" Framework, "Geneva" Server, Windows CardSpace "Geneva"를 포함합니다. Geneva Framework는 클레임 기반 응용 프로그램과 서비스를 작성하는 데 필요한 STS(보안 토큰 서비스)를 통해 발급되는 토큰 관련 도구와 사용자 지정 STS 및 Windows CardSpace 지원 응용 프로그램 작성 도구를 제공합니다. Geneva Server는 엔터프라이즈 STS이고, Geneva Framework는 엔터프라이즈 기능이 필요 없는 환경에서 사용할 사용자 지정 STS를 작성하는 데 사용됩니다. Windows CardSpace Geneva는 Windows 클라이언트 컴퓨터에서 ID 선택기 및 ID 공급자 역할을 하도록 발전된 Windows CardSpace의 새 버전입니다.

Geneva Framework에 대한 지난 칼럼에서 필자는 STS를 통해 발급되는 토큰을 기반으로 클레임 기반 Windows Communication Foundation(WCF) 서비스를 효과적으로 작성하는 방법을 설명한 바 있습니다. 이번 칼럼에서는 Geneva Framework를 사용하여 사용자 지정 STS를 작성해보겠습니다.

이 칼럼을 읽기 전에 Keith Brown과 Sesha Mani의 개발자를 위한 Geneva Framework 백서 및 필자의 지난 기사 "Geneva Framework: 클레임 기반 WCF 서비스 구축을 위한 더 나은 방법"을 먼저 읽으시기 바랍니다.

보안 토큰 서비스 입문

Geneva Server를 기반으로 하든지, Geneva Framework를 사용하여 작성되었든지 기본적으로 STS는 호출자를 인증하고 호출자를 나타내는 클레임을 전달하는 보안 토큰을 발행하는 역할을 합니다. 앞서 언급한 기사에서 STS 인증은 다음과 같은 몇 가지 시나리오를 지원한다고 설명한 내용을 기억하실 겁니다.

  • 관련 클레임을 인증하는 데 초점을 맞출 수 있도록 응용 프로그램 및 서비스를 인증 메커니즘에서 분리
  • 응용 프로그램 및 서비스를 복잡하게 만들지 않고도 여러 자격 증명 유형 지원
  • 각 도메인의 STS 간에 신뢰 관계를 설정함으로써 도메인으로 사용자를 인증하고 다른 도메인의 리소스에 대한 액세스 권한을 부여하는 페더레이션된 시나리오 지원
  • 인증된 사용자에게 다운스트림 서비스에 대한 액세스 권한을 부여하는 ID 위임 시나리오 지원
  • 응용 프로그램 및 서비스에서 관련 클레임을 인증에 사용할 수 있도록 클레임 변환 지원

이러한 모든 시나리오는 패시브 페더레이션(브라우저 기반) 또는 액티브 페더레이션(Windows 클라이언트 기반)을 기반으로 할 수 있습니다. 다음으로 각각의 시나리오를 자세히 알아보면서 Geneva Framework를 사용하여 작성하는 사용자 지정 STS에 관련 논리를 구현하는 방법을 설명하겠습니다.

STS의 구현 방법을 본격적으로 살펴보기 전에 먼저 몇 가지 기본 사항을 다시 한번 짚어보겠습니다. 액티브 페더레이션에 사용되는 STS는 WS-Federation Active Requestor Profile(WS-Federation TC 참조)과 (기본적으로) WS-Trust 사양(WS-Trust 1.3)의 구체화된 형태라고 할 수 있습니다.

WS-Trust에서는 계약을 크게 Issue, Validate, Renew 및 Cancel이라는 네 가지 작업으로 설명합니다. 이러한 작업은 각각 클라이언트에서 보안 토큰을 요청하거나 보안 토큰의 유효성을 검사하거나 만료된 보안 토큰을 갱신하거나 더 이상 사용하지 않는 보안 토큰을 취소하기 위해 호출됩니다. 각 작업은 RST(보안 토큰 요청)라는 메시지 형식으로 전송되고 WS-Trust 사양에 따라 RSTR(RST 응답)이라는 형식의 메시지를 반환합니다. 이 기사에서는 발급되는 토큰이 Security Assertion Markup Language(SAML) 1.1 또는 SAML 2.0 토큰이라는 전제 하에 설명합니다.

그림 1에는 액티브 토큰 발급에 사용되는 RST 및 RSTR의 핵심 내용이 나와 있습니다. RST 메시지에는 발급할 토큰의 형식(여기서는 SAML), 신뢰 당사자(RP)가 발급된 토큰에 포함하도록 요청한 클레임, URL과 RP를 식별하는 인증서를 비롯한 RP관련 정보(AppliesTo), RSTR을 통해 반환되는 소유 증명 키(증명 키)에 사용할 키 자료(선택 사항이며 그림에 나와 있지 않음) 등 보안 토큰을 요청하는 데 필요한 정보가 포함됩니다.

그림 1 액티브 페더레이션 시나리오의 토큰 발급

토큰이 성공적으로 발급된 경우 RSTR에 발급된 SAML 토큰과 증명 키(STS에서 사용 및 RSTR에 반환해야 할 증명 키를 지정하는 경우)가 포함됩니다. SAML 토큰에는 인증 대상자에 대한 관련 클레임이 포함되며 변조를 방지하기 위해 STS에 의해 서명되고 RP에 대한 증명 키가 암호화되어 포함됩니다. 또한 SAML 토큰 자체도 대상 수신자만 처리할 수 있도록 RP에 대해 암호화됩니다.

클라이언트는 증명 키를 사용하여 RP로 보내는 메시지에 서명합니다. RP가 SAML 토큰에 포함된 증명 키의 암호를 해독하지 못하면 메시지가 거부됩니다. 토큰에 포함된 증명 키가 메시지의 서명과 일치하면 RP에 대한 호출이 토큰을 요청한 당사자가 보낸 것으로 증명됩니다.

패시브 페더레이션 시나리오는 브라우저 기반 통신을 사용하는 WS-Federation Passive Requestor Profile을 기반으로 합니다. 그러나 기본 메시징 기능은 액티브 페더레이션 시나리오와 마찬가지로 WS-Trust를 기반으로 하며 RST는 STS URL에 대한 쿼리 문자열 매개 변수로 구성되고 RSTR는 일반적으로 RP에 폼 매개 변수로 게시됩니다. 패시브 STS 및 RP는 페더레이션 웹 처리기를 사용하여 이러한 매개 변수를 가로챕니다. 패시브 STS는 WS-Trust 요청을 직접 처리하거나 기본 WS-Trust 구현에 전달할 수 있습니다. 그림 2는 패시브 페더레이션 시나리오에서 RST와 RSTR이 어떻게 처리되는지를 보여 줍니다.

그림 2 패시브 페더레이션 시나리오의 토큰 발급

액티브 페더레이션 시나리오와 패시브 페더레이션 시나리오의 가장 큰 차이점 중 하나는 바로 발급되는 SAML 토큰의 형식입니다. 일반적으로 액티브 페더레이션은 "키 보유자" 형식의 주체 확인 방식을 사용하는 SAML 토큰을 기반으로 합니다. 즉, 앞서 설명한 것처럼 토큰을 보내는 클라이언트가 토큰을 요청한 주체임을 증명하기 위해 증명 키가 사용됩니다(ActAs 동작이라고도 함). 패시브 페더레이션의 경우 일반적으로 "소지인" 형식의 주체 확인 방식을 사용하는 SAML 토큰(소지인 토큰이라고도 함)을 기반으로 합니다. 이 형식의 토큰에는 증명 키가 포함되지 않으며 키가 없는 토큰으로 호출되기도 합니다. STS에서 토큰을 획득하여 RP로 전송하는 과정에서 보안은 전적으로 전송 방식에 의존합니다.

WS-Federation, WS-Trust, SAML 토큰 등의 개념은 앞으로 설명할 내용을 이해하는 데 있어서 중요합니다. 먼저 Geneva Framework를 사용하여 액티브 STS를 작성하는 방법을 설명하겠습니다. 그리고 패시브 STS 작성에 대해 설명하고 마지막으로 각각에 대해 확장된 시나리오를 몇 가지 소개합니다.

사용자 지정 액티브 STS 작성

그림 3과 같은 간단한 액티브 페더레이션 시나리오에서는 일반적으로 다음과 같은 참가자가 존재합니다.

  • 클라이언트에서 호출한 서비스인 RP
  • 마찬가지로 서비스로 구현되며 WS-Trust 프로토콜을 지원하는 단일 STS. 이 STS는 호출자를 인증하고 호출자를 식별하는 클레임이 포함된 보안 토큰을 발급합니다. ID 공급자 또는 IP-STS라고도 합니다.
  • 프록시를 사용하여 STS에 대해 인증 받고 발급된 토큰을 검색하고 인증 및 권한 부여를 위해 토큰을 발급한 RP에 메시지를 보내는 클라이언트(여기서는 Windows 기반 응용 프로그램)

fig03a.gif

그림 3 단일 RP와 액티브 IP-STS가 있는 간단한 페더레이션 시나리오

그림 4는 이 구현의 구동부를 보여 줍니다. 여기에는 사용자 지정 SecurityTokenService 구현, 페더레이션을 위한 런타임 초기화에 ServiceHost 확장(WSTrustServiceHost) 사용, WSTrustContract 형식의 파생형을 사용한 하나 이상의 WS-Trust 끝점 구성, 기타 ID 모델 런타임 관련 구성 설정이 포함됩니다. 다음 섹션에서는 Geneva Framework를 기반으로 구현된 사용자 지정 STS의 이러한 구성 요소를 각각 살펴보겠습니다.

그림 4 사용자 지정 액티브 STS 및 액티브 IP-STS 구현 아키텍처

SecurityTokenService 확장

Geneva Framework는 Microsoft.IdentityModel.SecurityTokenService 네임스페이스의 SecurityTokenService 형식을 통해 사용자 지정 STS를 작성하는 데 필요한 핵심 기능을 제공합니다. 이 추상 클래스는 RST 및 RSTR 메시지를 처리하고 보안 토큰을 생성하는 주요 작업을 담당합니다. 사용자 지정 STS 형식은 이 클래스를 상속하고 최소한 다음 기능을 제공합니다.

  • 사용자 지정 SecurityTokenServiceConfiguration 인스턴스를 사용하여 STS의 기본 기능 중 일부(뒷부분에서 설명)를 구성하는 생성자
  • 요청에 대한 대상 RP의 유효성을 검사하고 RP에 대해 적절한 암호화 자격 증명과 보안 토큰의 서명 자격 증명을 제공하기 위한 GetScope 재정의
  • 생성된 보안 토큰에 클레임을 제공하기 위한 GetOutputClaimsIdentity 재정의

그림 5에는 이러한 기능을 제공하는 간단한 사용자 지정 STS를 구현하기 위한 코드가 나와 있습니다. 그림 1과 그림 2에서 살펴본 액티브 STS의 통신 흐름을 떠올려 보십시오. STS 구현 형태인 IdentitySTS는 GetScope가 호출될 때 RST의 AppliesTo 요소가 실제로 신뢰할 수 있는 URI를 가리키는지 확인함으로써 들어오는 RST의 유효성을 검사합니다. STS에서는 토큰 발급이 가능한 신뢰할 수 있는 RP와 해당 인증서의 목록을 관리하게 됩니다. AppliesTo가 유효성 검사를 통과하면 GetScope는 범위의 EncryptingCredentials 속성(여기서는 "RPKey")을 적절한 인증서로 설정합니다. 또한 SigningCredentials 속성이 발급된 토큰에 서명하는 데 사용할 적절한 인증서로 설정됩니다. 이 속성 값은 일반적으로 STS의 개인 키(여기서는 "IPKey")가 됩니다.

그림 5 간단한 사용자 지정 STS 구현

public class IdentitySTS : SecurityTokenService
{
    public IdentitySTS(SecurityTokenServiceConfiguration config)
        : base( config )
    {
    }

    protected override IClaimsIdentity GetOutputClaimsIdentity(
        IClaimsPrincipal principal, RequestSecurityToken request, 
        Scope scope)
    {
        IClaimsIdentity claimsIdentity = new ClaimsIdentity();

        claimsIdentity.Claims.Add(new Claim(ClaimTypes.Name, 
            principal.Identity.Name));
        claimsIdentity.Claims.Add(new Claim(ClaimTypes.Role, "Users"));

        return claimsIdentity;
    }

    protected override Scope  GetScope(
        Microsoft.IdentityModel.Claims.IClaimsPrincipal principal, 
        RequestSecurityToken request)
    {

        Scope scope = new Scope(request);
        scope.EncryptingCredentials = this.GetCredentialsForAppliesTo(
                                                     request.AppliesTo);
        scope.SigningCredentials = new 
          X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, 
          StoreLocation.LocalMachine, "CN=IPKey"));
        return scope;
    }

    private X509EncryptingCredentials GetCredentialsForAppliesTo(Endpoint
        Address appliesTo)
    {
        if (appliesTo == null || appliesTo.Uri ==null || 
          string.IsNullOrEmpty(appliesTo.Uri.AbsolutePath))
        {
            throw new InvalidRequestException(
                "AppliesTo must be supplied in the RST.");
        }

        X509EncryptingCredentials creds = null;
        if (appliesTo.Uri.AbsoluteUri.StartsWith(
            "http://localhost:8000/RelyingPartyService"))
        {
            creds = new X509EncryptingCredentials(
                CertificateUtil.GetCertificate(StoreName.TrustedPeople, 
                StoreLocation.LocalMachine, 
                "CN=RPKey"));
        }
        else
            throw new InvalidRequestException(String.Format(
                "Invalid relying party address: {0}", 
                appliesTo.Uri.AbsoluteUri));

        return creds;
    }
}

GetOutputClaimsIdentity가 호출되면 인증된 호출자의 ID와 함께 ClaimsPrincipal이 런타임에 의해 전달됩니다. 이 ID는 대개 호출자에게 권한을 부여하기에 적합한 클레임이 있는지를 확인하는 데 사용됩니다. 그림 5에는 호출자에 대해 이름 클레임과 하드코드된 역할 클레임을 생성하여 ClaimsIdentity의 형식으로 반환하는 코드가 나와 있습니다. 이 ClaimsIdentity는 런타임에 토큰을 발급하는 데 사용할 클레임을 제공합니다.

다음 기능을 제공하도록 이 STS 구현을 확장할 수도 있습니다.

  • GetOutputClaimsIdentity에 사용자 지정 자격 증명 저장소에서 사용자를 조회하는 코드를 포함하여 추가 클레임 조회. 예를 들어 역할 목록, 전자 메일 주소와 같은 기타 관련 정보 또는 보다 세부적인 권한(만들기, 읽기, 업데이트 또는 삭제)을 나타내는 사용자 지정 클레임을 조회할 수 있습니다.
  • GetScope가 신뢰할 수 있는 모든 RP와 관련 인증서를 나열하는 사용자 지정 데이터베이스에서 AppliesTo URI 조회

STS 호스트 및 구성

WCF에 익숙한 독자라면 클라이언트에서 서비스로 메시지를 보내려면 끝점이 하나 이상 구성되어 있어야 한다는 것을 잘 아실 것입니다. STS의 경우 각 끝점에 사용할 서비스 계약이 Issue, Validate, Renew 및 Cancel 작업을 포함하는 WS-Trust 프로토콜을 기반으로 해야 합니다. 사실 STS로 구현할 수 있는 WS-Trust 프로토콜에는 두 가지 버전이 있습니다.

  • WS-Trust 1.3: WS-Trust 사양의 최신 버전
  • WS-Trust February 2005: 업계의 여러 파트너가 표준이 승인되기 전에 구현한 WS-Trust 버전

SecurityTokenService 형식에서 GetScope(), GetOutputClaimsIdentity() 등의 메서드에 대한 비동기 구현을 제공할 수도 있습니다. 이렇게 하면 인증서 액세스나 클레임 데이터와의 상호 작용과 같이 입/출력 양이 많은 작업의 확장성이 향상됩니다. STS의 끝점을 구성할 때는 끝점에 대해 노출할 계약을 선택해야 합니다. Microsoft.IdentityModel.Protocols 네임스페이스에는 STS 끝점에 대한 두 가지 계약, IWSTrust13SyncContract와 IWSTrustFeb2005SyncContract가 포함되어 있습니다. 그림 6은 이 두 계약 각각에 대해 하나씩 2개의 끝점이 있는 STS의 구성을 보여 줍니다. 이 두 계약은 비동기 프록시를 구현하는 데 사용할 수 있도록 비동기 버전(IWSTrust13AsyncContract 및 IWSTrustFeb2005AsyncContract)으로도 제공됩니다.

그림 6 여러 WS-Trust 끝점이 있는 STS 서비스 구성

<service name=
  "Microsoft.IdentityModel.Protocols.WSTrust.WSTrustServiceContract" 
  behaviorConfiguration="stsBehavior">
  <endpoint address="WSTrustFeb05" binding="wsHttpBinding" 
    contract="Microsoft.IdentityModel.Protocols.WSTrust.
    IWSTrustFeb2005SyncContract"/>
  <endpoint address="WSTrust13" binding="wsHttpBinding"  
    contract="Microsoft.IdentityModel.Protocols.WSTrust.
    IWSTrust13SyncContract"/>
</service>

STS는 기존 클라이언트에 설치된 이전 버전과 호환되도록 WS-Trust February 2005 기반 끝점을 제공해야 합니다. 두 계약을 구현하는 서비스 형식은 WSTrustServiceContract이며 Microsoft.IdentityModel.Protocols.WSTrust 네임스페이스에 포함되어 있습니다. 이 형식이 STS의 <service> 구성 섹션에서 참조되어야 합니다.

그림 4의 다이어그램에서 보듯이 <service> 구성과 해당 끝점은 올바른 WSTrustServiceContract 형식으로 호스트를 초기화하는 데 사용됩니다. 또한 이 형식은 호스트를 초기화하는 동안 사용자 지정 SecurityTokenService 구현에 대한 참조를 사용하여 초기화됩니다. 이러한 방법으로 런타임에서 메시지를 사용자 지정 STS에 전달하게 됩니다.

그림 6에서 두 STS 끝점은 모두 Windows 자격 증명을 사용하여 호출자를 인증합니다(wsHttpBinding의 기본 동작). STS는 대체 바인딩 구성을 사용하여 여러 끝점을 노출함으로써 다양한 자격 증명 형식을 지원할 수 있습니다. 이를 위해서는 각 자격 증명 형식별로 적절한 보안 토큰 처리기도 구성해야 합니다. 토큰 처리기 구성 설정에 대해서는 조금 뒤에 설명하도록 하겠습니다.

Geneva Framework는 STS 인스턴스를 호스트하는 데 사용할 수 있도록 사용자 지정 ServiceHost 형식, WSTrustServiceHost를 제공합니다. 다음 코드는 자체 호스팅 환경에서 WSTrustServiceHost 형식을 생성하는 방법을 보여 줍니다.

WSTrustServiceHost stsHost = 
  new WSTrustServiceHost(new IdentitySTSConfiguration());
stsHost.Open();

WSTrustServiceHost는 STS의 메타데이터 교환 동작을 지원하고 메타데이터 교환 끝점을 구성하기 위해 사용자 지정 SecurityTokenServiceConfiguration 인스턴스를 사용하여 WS-Trust 끝점이 있는 런타임을 초기화합니다.

IIS에서 호스트하는 경우 같은 결과를 얻기 위해 WSTrustServiceHostFactory 형식이 사용됩니다. .svc 파일에서 @ServiceHost 구성은 다음과 같이 factory 형식과 사용자 지정 SecurityTokenServiceConfiguration 형식을 지정합니다.

<%@ ServiceHost Factory="Microsoft.IdentityModel.Protocols.WSTrust. 
  WSTrustServiceHostFactory" 
  Service="STS.IdentitySTSConfiguration"  %>

factory는 활성화 시에 지정된 구성으로 WSTrustServiceHost를 초기화합니다.

사용자 지정 SecurityTokenServiceConfiguration 형식은 STS의 WSTrustServiceHost를 초기화하는 데 필요합니다. 그림 7은 IdentitySTSConfiguration이라는 사용자 지정 구현을 보여 줍니다.

그림 7 사용자 지정 SecurityTokenServiceConfiguration

public class IdentitySTSConfiguration: SecurityTokenServiceConfiguration
{

    public IdentitySTSConfiguration(): base("http://localhost:8010/sts")
    {

      this.TokenIssuerName = "http://localhost:8010/sts";

      this.SigningCredentials = new 
        X509SigningCredentials(CertificateUtil.GetCertificate(StoreName.My, 
        StoreLocation.LocalMachine, "CN=IPKey"));

      this.SecurityTokenService = typeof( IdentitySTS);

    }

}

이 형식은 STS에 대한 URI, 서명에 사용되는 자격 증명, 구성 관련 STS 형식에 대한 참조를 제공해야 합니다. STS에서 관리되는 카드를 발급할 경우 URL가 유효해야 Windows CardSpace에서 해당 카드를 가져올 수 있습니다. 기본 형식에는 TokenIssuerName에 전달할 문자열 값이 필요하지만 이 값을 하드코드하여 생성자에 전달하는 것보다는 구성에서 URI를 동적으로 설정할 수 있도록 코드에서 재정의하는 것이 좋습니다.

SecurityTokenServiceConfiguration 형식은 키 크기와 토큰 형식의 기본값을 설정하고 메타데이터에 대한 액세스를 차단하고 토큰 수명 주기 및 클럭 오차를 제어하고 사용자 지정 RST 및 RSTR 직렬화기를 설정하고 호출자를 인증하는 토큰 처리기를 구성하고 WS-Trust 끝점을 구성하는 데 사용할 수 있는 속성도 제공합니다.

다음은 <service> 구성 설정을 사용하는 대신 프로그래밍 방식으로 메타데이터 액세스를 차단하고 그림 6에 있는 것과 같은 WS-Trust 끝점을 초기화하는 방법을 보여 주는 예입니다.

IdentitySTSConfiguration config = new IdentitySTSConfiguration();
config.DisableWsdl = true;
config.TrustEndpoints.Add(new 
  ServiceHostEndpointConfiguration("WSTrustFeb05", new WSHttpBinding(),  
  typeof(IWSTrustFeb2005SyncContract)));
config.TrustEndpoints.Add(new ServiceHostEndpointConfiguration(
  "WSTrust13", new WSHttpBinding(), 
  typeof(IWSTrust13SyncContract)));

WSTrustServiceHost stsHost = new WSTrustServiceHost(config);

기본 SecurityTokenServiceConfiguration 형식은 <microsoft.identityModel> 구성 섹션도 읽어 관련 STS 구성 설정을 초기화합니다. 사용자 지정 STS에 대해 선언적으로 구성할 수 있는 속성에는 최대 클럭 오차, 인증 및 발급에 사용되는 보안 토큰 처리기, 클레임 인증 관리자, 발급자 이름 레지스트리 및 토큰 확인자가 있습니다. 그림 8에는 STS에 대해 구성된 몇 가지 유용한 설정이 나와 있습니다.

그림 8 STS에 대한 <microsoft.identityModel> 구성

<microsoft.identityModel>
  <maximumClockSkew value="00:05:00"/>
  <claimsAuthenticationManager type="STS.
    CustomClaimsAuthenticationManager, STS"/>
  <securityTokenHandlers>
    <remove type="Microsoft.IdentityModel.Tokens.
      WindowsUserNameSecurityTokenHandler, 
      Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35" />
    <add type="Microsoft.IdentityModel.Tokens.
      MembershipUserNameSecurityTokenHandler, 
      Microsoft.IdentityModel, Version=0.5.1.0, Culture=neutral, 
      PublicKeyToken=31bf3856ad364e35">
        <usernameSecurityTokenHandlerRequirement 
          membershipProvider="CustomProviders.CustomMembershipProvider, 
          CustomProviders, Version=1.0.0.0, Culture=neutral,
           PublicKeyToken=c03h5a64f15d0b3f" />
    </add>
  </securityTokenHandlers>
</microsoft.identityModel>

사용자 지정 ClaimsAuthenticationManager 형식은 비Windows 자격 증명에서 호출되기 때문에 GetOutputClaimsIdentity에서 클레임을 발급하기 전에 사용자 지정 ClaimsPrincipal 형식을 제공할 수 있습니다. 사용자 지정 보안 토큰 처리기는 구성하여 특정 처리기의 기본 동작을 재정의하는 설정을 제공하거나 특정 자격 증명 형식에 대해 선택된 보안 토큰 처리기를 변경할 수 있습니다.

보안 토큰 처리기

서비스 동작 구성에 따라 각 STS 끝점의 인증 및 권한 부여가 이루어지라고 생각하기 쉽습니다. 그러나 지난 기사에서 언급했듯이 Geneva Framework는 일반적인 방식과는 약간 다르게 작동합니다. 인증의 경우 <securityTokenHandlers> 컬렉션에서 들어오는 요청 인증에 사용 가능한 SecurityTokenHandler 형식을 지정합니다.

이 컬렉션에는 각 SecurityTokenHandler 형식별로 하나의 항목만 포함될 수 있습니다. 예를 들어 각각의 자격 증명 형식에 대한 요청을 처리하기 위한 KerberosSecurityTokenHandler, UserNameSecurityTokenHandler, X509SecurityTokenHandler, Saml11SecurityTokenHandler 또는 Saml2SecurityTokenHandler는 하나씩만 등록할 수 있습니다. STS 끝점에 UserName 자격 증명이 필요한 경우 등록되는 기본 UserNameSecurityTokenHandler는 WindowsUserNameSecurityTokenHandler입니다. 그림 8은 멤버 자격 공급자에 대한 관련 구성 설정을 포함하여 WindowsUserNameSecurityTokenHandler를 제거하고 그 대신 MembershipUserNameSecurityTokenHandler를 추가하는 코드를 보여 줍니다.

사용자 지정 SecurityTokenHandler 형식을 만들 수도 있습니다. 앞서 설명했듯이 토큰 범주와 일치하는 적절한 기본 클래스(예: UserNameSecurityTokenHandler)에서 파생되기만 한다면 기본 처리기를 새로운 사용자 지정 처리기로 바꿀 수 있습니다. 그림 9는 CustomUserNameSecurityTokenHandler라는 사용자 지정 UserNameSecurityTokenHandler 구현을 보여 주는 코드입니다.

그림 9 사용자 지정 UserNameSecurityTokenHandler

public class CustomUserNameSecurityTokenHandler:   
  UserNameSecurityTokenHandler
{
  public override ClaimsIdentityCollection ValidateToken(SecurityToken token)
  {
    UserNameSecurityToken userNameToken = token as UserNameSecurityToken;
    AuthenticateUser(userNameToken.UserName, userNameToken.Password);

    return new ClaimsIdentityCollection(new IClaimsIdentity[] {
      new ClaimsIdentity(
        new Claim(System.IdentityModel.Claims.ClaimTypes.Name,
         userNameToken.UserName), "CustomUserNameSecurityTokenHandler")});
  }

  public override bool CanValidateToken
  {
    get { return true; }
  }
}

사용자 지정 SecurityTokenHandler 구현에서 최소한 ValidateToken과 CanValidateToken은 반드시 재정의해야 합니다. ValidateToken 내에서 적절한 자격 증명 저장소에 대해 인증을 받아야 합니다. 이러한 인증의 결과는 요청 스레드의 ClaimsPrincipal에 첨부하기 위해 런타임에 반환할 수 있는 클레임 집합이어야 합니다.

fig10.gif

그림 10 단일 RP와 패시브 IP-STS가 있는 간단한 페더레이션 시나리오

CanValidateToken을 재정의하고 True를 반환하는 것도 매우 중요합니다. 이러한 재정의 과정이 없으면 토큰 처리기가 컬렉션에 등록되지 않고 호출되지도 않습니다.

사용자 지정 패시브 STS 작성

간단한 패시브 페더레이션 시나리오에서도 참가자는 그림 3의 액티브 페더레이션 시나리오와 동일하지만 클라이언트가 브라우저이고 RP가 웹 응용 프로그램이며 IP-STS도 HTTP 기반 통신을 처리하기 위해 웹 응용 프로그램을 접하게 된다는 차이가 있습니다. 그림 10은 패시브 페더레이션의 참가자 및 통신 흐름을 보여 줍니다.

이 시나리오의 구동부도 핵심 STS와 관련해서는 그림 4와 동일하지만 패시브 STS에서 인증을 처리하고 기본 STS 기능을 호출하는 방법에 확연한 차이가 있습니다. 그림 10의 다이어그램은 이러한 차이점을 전체적인 관점에서 보여 줍니다. 패시브 STS는 토큰 발급 프로세스의 보안에 SSL 암호화를 사용하는 웹 사이트로 구현됩니다. 기본 페이지(Default.aspx)는 액티브 STS와 동일하게 구성되는 기본 사용자 지정 STS와의 통신을 지원하는 컨트롤을 호스트합니다.

STS 사이트는 토큰을 발급하기 전에 호출자를 인증해야 하는데 이때 인증과 권한 부여에 기존 ASP.NET 구성이 사용됩니다. 그림 11의 STS 응용 프로그램은 폼 인증을 사용하도록 구성되어 있으므로 FormsAuthenticationModule로 인증 받지 않은 요청이 로그인 페이지(Login.aspx)로 리디렉션됩니다.

패시브 STS 시나리오의 경우에도 핵심 STS는 한 가지만 조금 변경하면 액티브 STS와 동일하게 구현할 수 있습니다. 패시브 STS의 경우 그림 5의 GetScope 재정의에서 ReplyToAddress 속성을 설정하여 STS가 토큰을 발급한 후에 리디렉션할 수 있도록 해야 합니다. 일반적으로 이 속성은 RST를 사용하여 제공되는 AppliesTo 주소에 따라 RP의 기본 페이지로 설정됩니다.

Scope scope = new Scope(request);
scope.ReplyToAddress = scope.AppliesToAddress + "/default.aspx";
// other scope settings

그림 11 폼 인증을 사용한 패시브 STS 아키텍처 구현

패시브 STS의 Geneva Framework 구성은 액티브 STS와 차이가 없습니다. 즉, SecurityTokenServiceConfiguration 형식을 사용하여 STS를 초기화(그림 7)하고 <microsoft.identityModel> 구성 섹션의 모든 관련 설정도 고려됩니다.

FederatedPassiveTokenService 컨트롤

Geneva Framework는 패시브 STS의 필요한 기능을 구현하는 컨트롤을 제공합니다. 이 컨트롤은 로그인 및 로그아웃 HTTP 요청을 각각 RST로 변환한 다음 기본 STS 구현을 호출하여 처리합니다. 또한 RSTR 응답을 처리하고 RP에 대한 리디렉션과 인증된 호출자에 대한 세션 쿠키 작성도 처리합니다.

이 컨트롤을 패시브 STS 사이트의 기본 페이지에 배치하고 다음과 같이 Service 속성을 사용자 지정 SecurityTokenServiceConfiguration 구현으로 설정합니다.

<idfx:FederatedPassiveTokenService ID="FederatedPassiveTokenService1" 
  runat="server" Service="STS.IdentityProviderSTSConfiguration, STS">
</idfx:FederatedPassiveTokenService>

이 컨트롤은 사용자에게 인증을 요구하고 PreRender 이벤트를 통해 인증 여부를 확인합니다. 사용자가 이 기본 페이지에 도달하기 전에 먼저 다른 위치로 리디렉션되어 인증을 받도록 STS 사이트를 적절히 구성해야 합니다.

인증된 사용자가 항상 이 기본 페이지로 이동되기만 하면 요청을 처리하는 데 다른 구성은 필요하지 않습니다. 이 컨트롤은 예외를 처리하고 로그인 및 로그아웃 요청을 연결하는 데 필요한 Error, PreSignInRequested, PostSignInRequested, PreSignOutRequested 및 PostSignOutRequested 이벤트도 제공합니다.

SessionAuthenticationModule

FederatedPassiveTokenService 컨트롤을 사용하는 대신 프로그래밍 방식으로 패시브 STS 기능을 지원할 수도 있습니다. 먼저 <microsoft.identityModel> 구성 섹션에서 페더레이션 인증을 사용하도록 설정합니다.

<microsoft.identityModel>
  <federatedAuthentication enabled="true"/>
</microsoft.identityModel>

다음으로 패시브 STS의 페더레이션 모듈인 Microsoft.IdentityModel.Web 네임스페이스의 SessionAuthenticationModule을 사용하도록 설정합니다.

<modules>
  <add name="SessionAuthentication" 
    type="Microsoft.IdentityModel.Web.SessionAuthenticationModule,
    Microsoft.IdentityModel, Version=0.5.1.0,
    Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
</modules>

그러면 STS 웹 사이트의 페이지 중 하나에 전송된 요청에 대한 FederatedPassiveTokenService 컨트롤과 같은 결과가 얻어집니다. 이 모듈은 인증되지 않은 호출자를 로그인 페이지로 리디렉션합니다. 그리고 로그인에 성공하면 호출자가 다시 원래 요청한 STS 페이지로 리디렉션됩니다. 이러한 프로그래밍 방식을 사용하면 개발자가 FederatedPassiveTokenService 컨트롤을 사용할 때보다 세부적으로 제어할 수 있습니다. 예를 들어 이 모듈은 초기화, 보안 토큰 관리, 로그인 및 로그아웃 기능과 상호 작용 할 수 있도록 ConfigurationLoading, ConfigurationLoaded, SecurityTokenReceived, SecurityTokenValidated, SessionSecurityTokenCreated, SessionSecurityTokenReceived, SignedIn, SigningOut, SignedOut, SignInError 및 SignOutError 이벤트를 제공합니다.

사용자 인증

STS 사이트는 지원되는 자격 증명 형식에 따라 사용자를 인증하는 기능을 합니다. WCF를 사용하여 구현된 액티브 STS의 경우 다양한 인증 메커니즘을 지원하도록 여러 끝점을 쉽게 구성할 수 있지만 패시브 STS의 경우에는 ASP.NET 웹 사이트 구성의 특성상 한 가지 인증 메커니즘만 지원할 수 있습니다. 따라서 지원되는 인증 메커니즘별로 별도의 패시브 STS 사이트를 제공해야 합니다. 물론 핵심 STS 구현은 모든 사이트에서 공유할 수 있습니다.

패시브 STS 인증은 ASP.NET 구성 기법을 기초로 합니다. 그 중에서 많이 사용되는 방식으로는 Windows 인증, 폼 인증 및 Windows CardSpace 인증을 들 수 있습니다. Windows 인증의 경우 다음과 같은 구성이 사용됩니다.

<authentication mode="Windows"/>
<authorization>
  <deny users="?"/>
</authorization>

사용자는 STS의 기본 페이지에 도달하기 전에 대화형 대화 상자를 통해 인증 받게 되므로 이 경우에는 사용자 지정 로그인 페이지가 필요하지 않습니다.

그림 11은 폼 인증을 사용한 예를 보여 줍니다. FormsAuthenticationModule은 인증되지 않은 호출을 로그인 페이지로 리디렉션합니다. 로그인 페이지에서는 사용자가 자격 증명을 입력할 수 있습니다. 로그인 페이지에서 인증되면 기본 STS 페이지로 리디렉션되고, 페더레이션 컨트롤이 원래 인증 요청을 처리합니다. 이 예에서 ASP.NET은 다음과 같이 구성할 수 있습니다.

<authentication mode="Forms"/>
<authorization>
  <deny users="?"/>
</authorization>

Windows CardSpace 인증의 경우 STS 사이트는 폼 인증을 사용하도록 구성할 수 있지만 로그인 페이지에 Windows CardSpace 인증을 위한 InformationCard 컨트롤이 포함됩니다.

클레임 변환

클레임 변환은 페더레이션 보안에 있어서 중요한 과정으로, 페더레이션 흐름의 다양한 위치에서 발생합니다. IP-STS와 RP가 같은 도메인에 속하는 간단한 페더레이션 시나리오에서 사용자가 인증 시에 제시하는 초기 ID 집합의 클레임을 RP가 호출을 인증하는 데 사용 가능한 클레임으로 변환하는 역할은 IP-STS가 담당합니다. 사용자는 지원되는 자격 증명 형식 중 하나를 제시하여 IP-STS에 대해 인증을 받을 수 있습니다. 이러한 자격 증명은 각각 자격 증명을 나타내는 클레임 집합으로 평가됩니다.

IP-STS는 이러한 클레임을 RP가 호출 인증에 사용하는 정규화된 응용 프로그램 클레임 집합으로 변환합니다. 변환된 클레임 집합은 역할일 수도 있고 만들기, 읽기, 업데이트 또는 삭제 권한과 같은 보다 세분화된 클레임일 수도 있습니다. 그림 12의 다이어그램은 Admin 사용자가 로그인하여 Role 클레임과 Create, Read, Update 및 Delete를 포함한 몇 가지 Action 클레임을 부여 받는 시나리오를 보여 줍니다.

fig12.gif

그림 12 IP-STS의 클레임 변환

이러한 클레임 변환 유형은 사용자에게 부여된 모든 클레임을 포함한 토큰이 STS에 대한 인증 결과로 생성되는 경우에 유용합니다. 그러나 현재 호출 컨텍스트와 관련 있는 클레임만 발급하여 클레임 수를 제한하거나 클레임의 개인 정보를 보호하거나 도메인 전체에서 페더레이션을 지원해야 하는 등의 경우에는 다른 클레임 변환 방식이 필요합니다.

인증된 호출자에게 RP가 제공하는 모든 기능과 관련한 많은 수의 클레임을 부여하는 것이 바람직하거나 적절하지 않은 경우도 있습니다. 클레임 목록이 너무 길어지는 문제 외에도 클레임은 컨텍스트 없이 발급되어서는 안 되고 호출 컨텍스트를 기준으로 부여해야 하기 때문입니다. 예를 들어 특정 사용자가 고객 주문과 관련한 작업을 수행할 때만 Delete 클레임을 부여하고 고객 레코드와 직접 상호 작용할 때는 Delete 클레임을 부여하지 않을 수 있습니다.

이러한 경우에는 RP가 IP-STS에서 클레임을 몇 개만 요청하여 호출자를 식별한 다음 호출의 컨텍스트에 필요한 특정한 추가 클레임 집합이 포함된 새 토큰을 요청하도록 하면 편리합니다. 예를 들어 사용자가 RP 서비스에서 DeleteCustomer 작업을 호출하는 경우 작업 권한을 부여하기 전에 RP는 IP-STS로부터 토큰을 전달하는 RP-STS를 호출하여 DeleteCustomer 작업 컨텍스트 내에서 Delete 클레임을 요청합니다. 클레임이 발급되면 호출이 인증됩니다. 그림 13의 다이어그램은 이러한 예를 보여 줍니다.

STS에서 발급되는 클레임을 RP와 직접 공유하면 안 되는 경우도 있습니다. 예를 들어 RP가 사용자의 나이를 알 수 있도록 Age 클레임을 발급하는 대신 RP가 IsOver13 클레임을 호출하여 호출자가 RP 기능을 사용할 수 있는 나이인지 확인할 수 있습니다. 이렇게 하면 Age 클레임의 실제 값이 STS 외부로 노출되지 않습니다. 물론 이 경우 ST가 개인 정보가 노출되지 않는 클레임을 제공하면서도 RP가 필요로 하는 데이터를 포함할 수 있어야 합니다.

fig13.gif

그림 13 RP-STS의 클레임 변환

클레임 변환은 특정 도메인에 속한 사용자에게 다른 도메인의 RP에 대한 액세스 권한이 부여되는 페더레이션 시나리오에서도 수행됩니다. 이 경우에는 사용자 도메인의 IP-STS와 RP를 소유한 도메인의 RP-STS가 사용됩니다.

또한 이 경우에 IP-STS는 RP-STS가 인식할 수 있는 동의 클레임도 부여합니다. 그러나 이러한 클레임은 RP 응용 프로그램에는 직접적으로 사용되지 않습니다. 대신 RP-STS는 다른 신뢰할 수 있는 클레임 집합을 RP 도메인에서 인식 가능한 클레임으로 변환합니다.

그림 14는 이러한 시나리오를 보여 줍니다. Joe가 토큰 없이 RP에 액세스하려 하면 자신이 속한 도메인(도메인 B)의 IP-STS에서 로그인하게 됩니다. RP에서 인식 가능한 클레임(이 예의 경우 RPClaim)이 요청되므로 IP-STS는 RP가 사용할 수 있는 토큰을 발급해야 함을 인식합니다. RP-STS가 이 토큰을 받으면 클레임을 RP별 클레임으로 변환합니다. 이 페더레이션 시나리오가 제대로 작동하려면 RP-STS와 IP-STS 간에 신뢰 관계가 설정되어 있어야 하고 IP-STS가 사용자에게 RP에 대한 액세스 권한을 부여하기 위해 발급해야 하는 클레임 집합에 대해 서로 동의가 이루어져야 합니다.

fig14.gif

그림 14 페더레이션 시나리오의 클레임 변환

요약

Geneva Framework는 Geneva Server와 같이 완전한 기능을 갖춘 STS 플랫폼이 필요하지 않기 때문에 자신만의 사용자 지정 STS를 작성하려는 개발자에게 유용한 유틸리티입니다. 그러나 Geneva Framework를 사용하더라도 사용자 지정 STS는 쉽게 작성할 수 있으며 노출을 줄일 수 있다면 항상 완전한 기능을 갖춘 STS를 사용하는 것이 좋습니다.

클레임 변환의 기본 원리가 동일하기 때문에 액티브 및 패시브 STS 구현의 통신 흐름도 플랫폼에 관계없이 동일합니다. STS 구현과 관련한 다른 개념으로는 ID 위임과 스텝업 인증이 있습니다. 이 둘을 비롯한 추가 개념에 대한 샘플과 설명서는 Geneva Framework SDK에 포함되어 있습니다.

Michele Leroux Bustamante는 IDesign Inc.의 수석 설계자이며, 샌디에이고의 Microsoft 지역 책임자로 활동하고 있고 Connected Systems 부문 Microsoft MVP이기도 합니다. 최근 저서는 Learning WCF입니다. 문의 사항이 있으면 mlb@idesign.net으로 전자 메일을 보내거나 idesign.net을 방문하십시오. Michele의 블로그는 dasblonde.net입니다.