다음을 통해 공유


페더레이션

이 항목에서는 페더레이션 보안의 개념에 대한 간략한 개요를 제공합니다. 또한 페더레이션 보안 아키텍처를 배포하기 위한 WCF(Windows Communication Foundation) 지원에 대해서도 설명합니다. 페더레이션을 설명하는 샘플 애플리케이션에 대해서는 페더레이션 샘플을 참조하세요.

페더레이션 보안 정의

페더레이션 보안을 사용하면 클라이언트가 액세스 중인 서비스, 관련 인증, 권한 부여 절차를 서로 확실히 구분할 수 있습니다. 페더레이션 보안을 통해 여러 신뢰 영역에 있는 여러 시스템, 네트워크 및 조직 간에 협업을 수행할 수도 있습니다.

WCF에서는 페더레이션 보안을 사용하는 분산 시스템을 구축 및 배포하기 위한 지원을 제공합니다.

페더레이션 보안 아키텍처의 요소

다음 표에 설명된 것처럼 페더레이션 보안 아키텍처에는 세 가지 요소가 있습니다.

요소 설명
도메인/영역 보안 관리 또는 신뢰의 단일 단위입니다. 일반 도메인은 단일 조직을 포함할 수 있습니다.
페더레이션 설정된 신뢰가 있는 도메인의 컬렉션입니다. 신뢰 수준은 다른 경우도 있지만 일반적으로 인증 및 권한 부여가 포함됩니다. 일반적인 페더레이션은 리소스 집합에 대한 공유 액세스에서 신뢰가 설정된 여러 조직을 포함할 수 있습니다.
STS(보안 토큰 서비스) 보안 토큰을 발급하는 웹 서비스. 이 웹 서비스에서 신뢰하는 증거를 기반으로 누구나 이 어설션을 신뢰할 수 있도록 만듭니다. 이는 도메인 간의 신뢰를 조정하는 기준을 형성합니다.

예제 시나리오

다음 그림에서는 페더레이션 보안의 예제를 보여 줍니다.

Diagram showing a typical federated security scenario.

이 시나리오에는 A와 B라는 두 조직이 있습니다. 조직 B에는 조직 A의 일부 사용자가 가치 있게 여기는 웹 리소스(웹 서비스)가 있습니다.

참고 항목

이 섹션에서는 ‘리소스’, ‘서비스’ 및 ‘웹 서비스’라는 용어를 번갈아 사용합니다.

일반적으로 조직 A의 사용자는 조직 B의 서비스에 액세스하기 전에 일부 유효한 인증 형식을 제공해야 합니다. 뿐만 아니라 해당 사용자는 조직 B에서 특정 리소스에 액세스하려면 권한을 부여받아야 할 수도 있습니다. 이 문제를 해결하고 조직 A의 사용자가 조직 B의 리소스에 액세스할 수 있도록 하기 위한 한 가지 방법은 다음과 같습니다.

  • 조직 A의 사용자는 조직 B와 함께 자격 증명(사용자 이름 및 암호)을 등록합니다.

  • 리소스에 액세스하는 동안 조직 A의 사용자는 자격 증명을 조직 B에 제공하고, 리소스에 액세스하기 전에 인증됩니다.

이 접근 방식에는 세 가지 중대한 단점이 있습니다.

  • 조직 B는 해당 로컬 사용자의 자격 증명뿐만 아니라 조직 A의 사용자 자격 증명도 관리해야 합니다.

  • 조직 A의 사용자는 조직 A 내의 리소스에 대한 액세스 권한을 얻기 위해 일반적으로 사용하는 자격 증명 외에 추가 자격 증명 집합도 유지 관리(추가 사용자 이름 및 암호를 기억)해야 합니다. 이렇게 되면 사용자는 대개 여러 서비스 사이트에서 동일한 사용자 이름과 암호를 사용하게 되며, 이것은 취약한 보안 방법입니다.

  • 여러 조직이 조직 B의 리소스를 가치 있는 것으로 인식함에 따라 아키텍처는 확장되지 않습니다.

위에 언급한 단점을 해결하는 대체 접근 방식은 페더레이션 보안을 사용하는 것입니다. 이러한 접근 방식으로 조직 A와 B는 신뢰 관계를 구축하고, 구축된 신뢰 관계를 조정하기 위해 STS(보안 토큰 서비스)를 사용합니다.

페더레이션 보안 아키텍처에서, 조직 A의 사용자는 조직 B의 STS에서 발급된 유효한 보안 토큰(특정 서비스에 대한 액세스 권한을 부여하고 인증)을 제공해야 하는 조직 B의 웹 서비스에 액세스할지 여부를 알고 있습니다.

사용자는 STS B에 연결하여 STS와 관련된 정책으로부터 다른 수준의 간접 참조를 받습니다. STS A(클라이언트 신뢰 영역)에서 발급한 유효한 보안 토큰을 제공해야 STS B가 보안 토큰을 발급할 수 있습니다. 이는 두 조직 간에 자연스럽게 구축된 신뢰 관계이며, 조직 B가 조직 A의 사용자 ID를 관리할 필요가 없음을 의미합니다. 사실상 STS B에는 일반적으로 null issuerAddressissuerMetadataAddress가 있습니다. 자세한 내용은 방법: 로컬 발급자 구성을 참조하세요. 이 경우에는 클라이언트에서 STS A를 찾기 위해 로컬 정책을 확인합니다. 이 구성을 ‘홈 영역 페더레이션’이라 하며, STS B가 STS A의 정보를 유지 관리할 필요가 없기 때문에 스케일링 기능이 좋아집니다.

그런 다음 사용자는 조직 A의 STS에 연결하고, 조직 A 내의 기타 리소스에 대한 액세스 권한을 얻기 위해 일반적으로 사용하는 인증 자격 증명을 제공함으로써 보안 토큰을 가져옵니다. 이는 또한 사용자가 여러 자격 증명 집합을 유지 관리해야 하거나 여러 서비스 사이트에서 동일한 자격 증명 집합을 사용하는 문제를 줄여줍니다.

사용자는 STS A로부터 가져온 보안 토큰을 STS B에 제공합니다. 조직 B에서는 사용자 요청에 대한 권한 부여를 수행하고, 자체 보안 토큰 집합으로부터 사용자에게 보안 토큰을 발급합니다. 그런 다음 사용자는 토큰을 조직 B의 리소스에 제공하고 서비스에 액세스합니다.

WCF의 페더레이션 보안을 위한 지원

WCF는 <wsFederationHttpBinding>을 통해 페더레이션 보안 아키텍처를 배포하기 위한 턴키 지원을 제공합니다.

<wsFederationHttpBinding> 요소는 안전하고 안정적이며 상호 운용 가능한 바인딩을 제공합니다. 이 바인딩은 인코딩을 위한 통신 형식으로 텍스트와 XML을 사용하여 요청-회신 통신 스타일을 위한 기본 전송 메커니즘으로 HTTP를 사용해야 합니다.

페더레이션 보안 시나리오에서 <wsFederationHttpBinding>을 사용하면 다음 섹션에서 설명하는 것처럼 논리적으로 독립된 두 개의 단계로 분리될 수 있습니다.

1단계: 디자인 단계

디자인 단계에서 클라이언트는 ServiceModel Metadata 유틸리티 도구(Svcutil.exe)를 사용하여 서비스 엔드포인트를 노출하는 정책을 읽고, 서비스의 인증 및 권한 부여 요구 사항을 수집합니다. 적절한 프록시는 클라이언트에서 다음 페더레이션 보안 통신 패턴을 만들기 위해 생성됩니다.

  • 클라이언트 신뢰 영역의 STS로부터 보안 토큰을 가져옵니다.

  • 서비스 신뢰 영역의 STS에 대해 토큰을 제공합니다.

  • 서비스 신뢰 영역에서 STS로부터 보안 토큰을 가져옵니다.

  • 서비스에 대한 토큰을 제시하여 서비스에 액세스합니다.

2단계: 런타임 단계

런타임 단계에서 클라이언트는 WCF 클라이언트 클래스의 개체를 인스턴스화하며, WCF 클라이언트를 사용하여 호출을 합니다. WCF의 기본 프레임워크는 페더레이션 보안 통신 패턴에서 이전에 언급한 단계를 처리하며, 클라이언트는 이를 통해 서비스를 원활하게 사용할 수 있습니다.

WCF를 사용하여 샘플 구현

다음 그림에서는 WCF의 기본적인 지원을 사용하여 페더레이션 보안 아키텍처에 대한 샘플 구현을 보여 줍니다.

Diagram showing a sample Federation security implementation.

예제 MyService

ph x="1" /> 서비스는 MyServiceEndpoint를 통해 단일 엔드포인트를 노출합니다. 다음 그림에서는 엔드포인트와 연관된 주소, 바인딩 및 계약을 보여 줍니다.

Diagram showing the MyServiceEndpoint details.

서비스 엔드포인트 MyServiceEndpoint<wsFederationHttpBinding>를 사용하며, STS B에서 발급한 accessAuthorized 클레임과 함께 유효한 SAML(Security Assertions Markup Language) 토큰을 필요로 합니다.

<system.serviceModel>  
  <services>  
    <service type="FederationSample.MyService"
        behaviorConfiguration='MyServiceBehavior'>  
        <endpoint address=""  
            binding=" wsFederationHttpBinding"  
            bindingConfiguration='MyServiceBinding'  
            contract="Federation.IMyService" />  
   </service>  
  </services>  
  
  <bindings>  
    <wsFederationHttpBinding>  
    <!-- This is the binding used by MyService. It redirects   
    clients to STS-B. -->  
      <binding name='MyServiceBinding'>  
        <security mode="Message">  
           <message issuedTokenType=  
"http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">  
           <issuer address="http://localhost/FederationSample/STS-B/STS.svc" />  
            <issuerMetadata
           address=  
"http://localhost/FederationSample/STS-B/STS.svc/mex" />  
         <requiredClaimTypes>  
            <add claimType="http://tempuri.org:accessAuthorized" />  
         </requiredClaimTypes>  
        </message>  
      </security>  
      </binding>  
    </wsFederationHttpBinding>  
  </bindings>  
  
  <behaviors>  
    <behavior name='MyServiceBehavior'>  
      <serviceAuthorization
operationRequirementType="FederationSample.MyServiceOperationRequirement, MyService" />  
       <serviceCredentials>  
         <serviceCertificate findValue="CN=FederationSample.com"  
         x509FindType="FindBySubjectDistinguishedName"  
         storeLocation='LocalMachine'  
         storeName='My' />  
      </serviceCredentials>  
    </behavior>  
  </behaviors>  
</system.serviceModel>  

참고 항목

MyService에서 필요로 하는 클레임에 대해 미세한 지점이 언급되어야 합니다. 두 번째 그림에서는 MyService에는 accessAuthorized 클레임과 함께 SAML 토큰이 필요함을 나타냅니다. 좀 더 구체적으로 설명하면 이는 MyService에서 필요로 하는 클레임 형식을 지정합니다. 이 클레임 형식의 정규화된 이름은 http://tempuri.org:accessAuthorized(연관 네임스페이스 포함)이며, 서비스 구성 파일에서 사용합니다. 이 클레임의 값은 이 클레임의 존재를 표시하고, STS B에 의해 true로 설정된다고 가정합니다.

런타임에 이 정책은 MyServiceOperationRequirement의 일부로 구현되는 MyService 클래스에 의해 적용됩니다.

using System.Collections.Generic;
using System.IdentityModel.Claims;
using System.IdentityModel.Policy;
using System.IdentityModel.Tokens;
using System.Security.Cryptography.X509Certificates;
using System.ServiceModel;
Imports System.Collections.Generic
Imports System.IdentityModel.Claims
Imports System.IdentityModel.Policy
Imports System.IdentityModel.Tokens
Imports System.Security.Cryptography.X509Certificates
Imports System.ServiceModel
Imports System.ServiceModel.Channels
Imports System.ServiceModel.Security.Tokens
Imports System.Text
public class myServiceAuthorizationManager : ServiceAuthorizationManager
{
    // Override the CheckAccess method to enforce access control requirements.
    public override bool CheckAccess(OperationContext operationContext)
    {
        AuthorizationContext authContext =
        operationContext.ServiceSecurityContext.AuthorizationContext;
        if (authContext.ClaimSets == null) return false;
        if (authContext.ClaimSets.Count != 1) return false;
        ClaimSet myClaimSet = authContext.ClaimSets[0];
        if (!IssuedBySTS_B(myClaimSet)) return false;
        if (myClaimSet.Count != 1) return false;
        Claim myClaim = myClaimSet[0];
        if (myClaim.ClaimType ==
          "http://www.tmpuri.org:accessAuthorized")
        {
            string resource = myClaim.Resource as string;
            if (resource == null) return false;
            if (resource != "true") return false;
            return true;
        }
        else
        {
            return false;
        }
    }

    // This helper method checks whether SAML Token was issued by STS-B.
    // It compares the Thumbprint Claim of the Issuer against the
    // Certificate of STS-B.
    private bool IssuedBySTS_B(ClaimSet myClaimSet)
    {
        ClaimSet issuerClaimSet = myClaimSet.Issuer;
        if (issuerClaimSet == null) return false;
        if (issuerClaimSet.Count != 1) return false;
        Claim issuerClaim = issuerClaimSet[0];
        if (issuerClaim.ClaimType != ClaimTypes.Thumbprint)
            return false;
        if (issuerClaim.Resource == null) return false;
        byte[] claimThumbprint = (byte[])issuerClaim.Resource;
        // It is assumed that stsB_Certificate is a variable of type
        // X509Certificate2 that is initialized with the Certificate of
        // STS-B.
        X509Certificate2 stsB_Certificate = GetStsBCertificate();
        byte[] certThumbprint = stsB_Certificate.GetCertHash();
        if (claimThumbprint.Length != certThumbprint.Length)
            return false;
        for (int i = 0; i < claimThumbprint.Length; i++)
        {
            if (claimThumbprint[i] != certThumbprint[i]) return false;
        }
        return true;
    }
Public Class myServiceAuthorizationManager
    Inherits ServiceAuthorizationManager

    ' Override the CheckAccess method to enforce access control requirements.
    Public Overloads Overrides Function CheckAccess(ByVal operationContext As OperationContext) As Boolean
        Dim authContext = operationContext.ServiceSecurityContext.AuthorizationContext
        If authContext.ClaimSets Is Nothing Then
            Return False
        End If

        If authContext.ClaimSets.Count <> 1 Then
            Return False
        End If

        Dim myClaimSet = authContext.ClaimSets(0)
        If Not IssuedBySTS_B(myClaimSet) Then
            Return False
        End If
        If myClaimSet.Count <> 1 Then
            Return False
        End If
        Dim myClaim = myClaimSet(0)
        If myClaim.ClaimType = "http://www.tmpuri.org:accessAuthorized" Then
            Dim resource = TryCast(myClaim.Resource, String)
            If resource Is Nothing Then
                Return False
            End If
            If resource <> "true" Then
                Return False
            End If
            Return True
        Else
            Return False
        End If
    End Function

    ' This helper method checks whether SAML Token was issued by STS-B.     
    ' It compares the Thumbprint Claim of the Issuer against the 
    ' Certificate of STS-B. 
    Private Function IssuedBySTS_B(ByVal myClaimSet As ClaimSet) As Boolean
        Dim issuerClaimSet = myClaimSet.Issuer
        If issuerClaimSet Is Nothing Then
            Return False
        End If
        If issuerClaimSet.Count <> 1 Then
            Return False
        End If
        Dim issuerClaim = issuerClaimSet(0)
        If issuerClaim.ClaimType <> ClaimTypes.Thumbprint Then
            Return False
        End If
        If issuerClaim.Resource Is Nothing Then
            Return False
        End If
        Dim claimThumbprint() = CType(issuerClaim.Resource, Byte())
        ' It is assumed that stsB_Certificate is a variable of type 
        ' X509Certificate2 that is initialized with the Certificate of 
        ' STS-B.
        Dim stsB_Certificate = GetStsBCertificate()
        Dim certThumbprint() = stsB_Certificate.GetCertHash()
        If claimThumbprint.Length <> certThumbprint.Length Then
            Return False
        End If
        For i = 0 To claimThumbprint.Length - 1
            If claimThumbprint(i) <> certThumbprint(i) Then
                Return False
            End If
        Next i
        Return True
    End Function

STS B

다음 그림에서는 STS B를 보여 줍니다. 위에서 설명한 것처럼 STS(보안 토큰 서비스)도 웹 서비스이며 이와 연관된 엔드포인트, 정책 등을 가질 수 있습니다.

Diagram showing security token service B.

STS B는 보안 토큰을 요청하는 데 사용할 수 있는 STSEndpoint라는 단일 엔드포인트를 노출합니다. 특히 STS B는 서비스에 액세스하기 위해 accessAuthorized 클레임과 함께 MyService 서비스 사이트에 제공할 수 있는 SAML 토큰을 발급합니다. 그러나 STS B를 사용하려면 userAuthenticated 클레임이 포함된 STS A에서 발급한 유효한 SAML 토큰을 제공해야 합니다. 이는 STS 구성에서 선언적으로 지정됩니다.

<system.serviceModel>  
  <services>  
    <service type="FederationSample.STS_B" behaviorConfiguration=  
     "STS-B_Behavior">  
    <endpoint address=""  
              binding="wsFederationHttpBinding"  
              bindingConfiguration='STS-B_Binding'  
      contract="FederationSample.ISts" />  
    </service>  
  </services>  
  <bindings>  
    <wsFederationHttpBinding>  
    <!-- This is the binding used by STS-B. It redirects clients to   
         STS-A. -->  
      <binding name='STS-B_Binding'>  
        <security mode='Message'>  
          <message issuedTokenType="http://docs.oasis-open.org/wss/oasis-wss-saml-token-profile-1.1#SAMLV1.1">  
          <issuer address='http://localhost/FederationSample/STS-A/STS.svc' />  
          <issuerMetadata address='http://localhost/FederationSample/STS-A/STS.svc/mex'/>  
          <requiredClaimTypes>  
            <add claimType='http://tempuri.org:userAuthenticated'/>  
          </requiredClaimTypes>  
          </message>  
        </security>  
    </binding>  
   </wsFederationHttpBinding>  
  </bindings>  
  <behaviors>  
  <behavior name='STS-B_Behavior'>  
    <serviceAuthorization   operationRequirementType='FederationSample.STS_B_OperationRequirement, STS_B' />  
    <serviceCredentials>  
      <serviceCertificate findValue='CN=FederationSample.com'  
      x509FindType='FindBySubjectDistinguishedName'  
       storeLocation='LocalMachine'  
       storeName='My' />  
     </serviceCredentials>  
   </behavior>  
  </behaviors>  
</system.serviceModel>  

참고 항목

또한 userAuthenticated 클레임은 STS B에서 필요로 하는 클레임 형식입니다. 이 클레임 형식의 정규화된 이름은 http://tempuri.org:userAuthenticated(연관 네임스페이스 포함)이며, STS 구성 파일에서 사용합니다. 이 클레임의 값은 이 클레임의 존재를 표시하고 STS A에 의해 true로 설정된다고 가정합니다.

런타임에 STS_B_OperationRequirement 클래스는 STS B의 일부로 구현되는 이 정책을 적용합니다.

public class STS_B_AuthorizationManager : ServiceAuthorizationManager
{

    // Override AccessCheck to enforce access control requirements.
    public override bool CheckAccess(OperationContext operationContext)
    {
        AuthorizationContext authContext =
        operationContext.ServiceSecurityContext.AuthorizationContext;
        if (authContext.ClaimSets == null) return false;
        if (authContext.ClaimSets.Count != 1) return false;
        ClaimSet myClaimSet = authContext.ClaimSets[0];
        if (!IssuedBySTS_A(myClaimSet)) return false;
        if (myClaimSet.Count != 1) return false;
        Claim myClaim = myClaimSet[0];
        if (myClaim.ClaimType == "http://www.tmpuri.org:userAuthenticated")
        {
            string resource = myClaim.Resource as string;
            if (resource == null) return false;
            if (resource != "true") return false;
            return true;
        }
        else
        {
            return false;
        }
    }

    // This helper method checks whether SAML Token was issued by STS-A.
    // It compares the Thumbprint Claim of the Issuer against the
    // Certificate of STS-A.
    private bool IssuedBySTS_A(ClaimSet myClaimSet)
    {
        ClaimSet issuerClaimSet = myClaimSet.Issuer;
        if (issuerClaimSet == null) return false;
        if (issuerClaimSet.Count != 1) return false;
        Claim issuerClaim = issuerClaimSet[0];
        if (issuerClaim.ClaimType != ClaimTypes.Thumbprint) return false;
        if (issuerClaim.Resource == null) return false;
        byte[] claimThumbprint = (byte[])issuerClaim.Resource;
        // It is assumed that stsA_Certificate is a variable of type X509Certificate2
        // that is initialized with the Certificate of STS-A.
        X509Certificate2 stsA_Certificate = GetStsACertificate();

        byte[] certThumbprint = stsA_Certificate.GetCertHash();
        if (claimThumbprint.Length != certThumbprint.Length) return false;
        for (int i = 0; i < claimThumbprint.Length; i++)
        {
            if (claimThumbprint[i] != certThumbprint[i]) return false;
        }
        return true;
    }
Public Class STS_B_AuthorizationManager
    Inherits ServiceAuthorizationManager

    ' Override AccessCheck to enforce access control requirements.
    Public Overloads Overrides Function CheckAccess(ByVal operationContext As OperationContext) As Boolean
        Dim authContext = operationContext.ServiceSecurityContext.AuthorizationContext
        If authContext.ClaimSets Is Nothing Then
            Return False
        End If
        If authContext.ClaimSets.Count <> 1 Then
            Return False
        End If
        Dim myClaimSet = authContext.ClaimSets(0)
        If Not IssuedBySTS_A(myClaimSet) Then
            Return False
        End If
        If myClaimSet.Count <> 1 Then
            Return False
        End If
        Dim myClaim = myClaimSet(0)
        If myClaim.ClaimType = "http://www.tmpuri.org:userAuthenticated" Then
            Dim resource = TryCast(myClaim.Resource, String)
            If resource Is Nothing Then
                Return False
            End If
            If resource <> "true" Then
                Return False
            End If
            Return True
        Else
            Return False
        End If
    End Function

    ' This helper method checks whether SAML Token was issued by STS-A. 
    ' It compares the Thumbprint Claim of the Issuer against the 
    ' Certificate of STS-A.
    Private Function IssuedBySTS_A(ByVal myClaimSet As ClaimSet) As Boolean
        Dim issuerClaimSet = myClaimSet.Issuer
        If issuerClaimSet Is Nothing Then
            Return False
        End If
        If issuerClaimSet.Count <> 1 Then
            Return False
        End If
        Dim issuerClaim = issuerClaimSet(0)
        If issuerClaim.ClaimType <> ClaimTypes.Thumbprint Then
            Return False
        End If
        If issuerClaim.Resource Is Nothing Then
            Return False
        End If
        Dim claimThumbprint() = CType(issuerClaim.Resource, Byte())
        ' It is assumed that stsA_Certificate is a variable of type X509Certificate2
        ' that is initialized with the Certificate of STS-A.
        Dim stsA_Certificate = GetStsACertificate()

        Dim certThumbprint() = stsA_Certificate.GetCertHash()
        If claimThumbprint.Length <> certThumbprint.Length Then
            Return False
        End If
        For i = 0 To claimThumbprint.Length - 1
            If claimThumbprint(i) <> certThumbprint(i) Then
                Return False
            End If
        Next i
        Return True
    End Function

액세스가 확인되면 STS B는 accessAuthorized 클레임과 함께 SAML 토큰을 발급합니다.

// Create the list of SAML Attributes.
List<SamlAttribute> samlAttributes = new List<SamlAttribute>();

// Add the accessAuthorized claim.
List<string> strList = new List<string>();
strList.Add("true");
samlAttributes.Add(new SamlAttribute("http://www.tmpuri.org",
"accessAuthorized",
strList));

// Create the SAML token with the accessAuthorized claim. It is assumed that
// the method CreateSamlToken() is implemented as part of STS-B.
SamlSecurityToken samlToken = CreateSamlToken(
    proofToken,
    issuerToken,
    samlConditions,
    samlSubjectNameFormat,
    samlSubjectEmailAddress,
    samlAttributes);
' Create the list of SAML Attributes.
Dim samlAttributes As New List(Of SamlAttribute)()

' Add the accessAuthorized claim.
Dim strList As New List(Of String)()
strList.Add("true")
samlAttributes.Add(New SamlAttribute("http://www.tmpuri.org", "accessAuthorized", strList))

' Create the SAML token with the accessAuthorized claim. It is assumed that 
' the method CreateSamlToken() is implemented as part of STS-B.
Dim samlToken = CreateSamlToken(proofToken, _
                                issuerToken, _
                                samlConditions, _
                                samlSubjectNameFormat, _
                                samlSubjectEmailAddress, _
                                samlAttributes)

STS A

다음 그림은 STS A를 보여 줍니다.

Federation

STS B와 마찬가지로 STS A도 보안 토큰을 발급하고, 이를 위해 단일 엔드포인트를 노출하는 웹 서비스입니다. 그러나 이는 다른 바인딩(wsHttpBinding)을 사용하며, 사용자가 emailAddress 클레임과 함께 유효한 CardSpace를 제공해야 합니다. 그 결과, STS A가 userAuthenticated 클레임과 함께 SAML 토큰을 발급합니다. 이는 서비스 구성에서 선언적으로 지정됩니다.

<system.serviceModel>  
  <services>  
    <service type="FederationSample.STS_A" behaviorConfiguration="STS-A_Behavior">  
      <endpoint address=""  
                binding="wsHttpBinding"  
                bindingConfiguration="STS-A_Binding"  
                contract="FederationSample.ISts">  
       <identity>  
       <certificateReference findValue="CN=FederationSample.com"
                       x509FindType="FindBySubjectDistinguishedName"  
                       storeLocation="LocalMachine"
                       storeName="My" />  
       </identity>  
    </endpoint>  
  </service>  
</services>  
  
<bindings>  
  <wsHttpBinding>  
  <!-- This is the binding used by STS-A. It requires users to present  
   a CardSpace. -->  
    <binding name='STS-A_Binding'>  
      <security mode='Message'>  
        <message clientCredentialType="CardSpace" />  
      </security>  
    </binding>  
  </wsHttpBinding>  
</bindings>  
  
<behaviors>  
  <behavior name='STS-A_Behavior'>  
    <serviceAuthorization operationRequirementType=  
     "FederationSample.STS_A_OperationRequirement, STS_A" />  
      <serviceCredentials>  
  <serviceCertificate findValue="CN=FederationSample.com"  
                     x509FindType='FindBySubjectDistinguishedName'  
                     storeLocation='LocalMachine'  
                     storeName='My' />  
      </serviceCredentials>  
    </behavior>  
  </behaviors>  
</system.serviceModel>  

런타임에 STS_A_OperationRequirement 클래스는 STS A의 일부로 구현되는 이 정책을 적용합니다.


public class STS_A_AuthorizationManager : ServiceAuthorizationManager
{
    // Override AccessCheck to enforce access control requirements.
    public override bool CheckAccess(OperationContext operationContext)
    {
        AuthorizationContext authContext =
        operationContext.ServiceSecurityContext.AuthorizationContext;
        if (authContext.ClaimSets == null) return false;
        if (authContext.ClaimSets.Count != 1) return false;
        ClaimSet myClaimSet = authContext.ClaimSets[0];
        if (myClaimSet.Count != 1) return false;
        Claim myClaim = myClaimSet[0];
        if ((myClaim.ClaimType ==
        @"http://schemas.microsoft.com/ws/2005/05/identity/claims:EmailAddress") &&
        (myClaim.Right == Rights.PossessProperty))
        {
            string emailAddress = myClaim.Resource as string;
            if (emailAddress == null) return false;
            if (!IsValidEmailAddress(emailAddress)) return false;
            return true;
        }
        else
        {
            return false;
        }
    }

    // This helper method performs a rudimentary check for whether
    //a given email is valid.
    private static bool IsValidEmailAddress(string emailAddress)
    {
        string[] splitEmail = emailAddress.Split('@');
        if (splitEmail.Length != 2) return false;
        if (!splitEmail[1].Contains(".")) return false;
        return true;
    }
}
Public Class STS_A_AuthorizationManager
    Inherits ServiceAuthorizationManager

    ' Override AccessCheck to enforce access control requirements.
    Public Overloads Overrides Function CheckAccess(ByVal operationContext As OperationContext) As Boolean
        Dim authContext = operationContext.ServiceSecurityContext.AuthorizationContext
        If authContext.ClaimSets Is Nothing Then
            Return False
        End If
        If authContext.ClaimSets.Count <> 1 Then
            Return False
        End If
        Dim myClaimSet = authContext.ClaimSets(0)
        If myClaimSet.Count <> 1 Then
            Return False
        End If
        Dim myClaim = myClaimSet(0)
        If myClaim.ClaimType = "http://schemas.microsoft.com/ws/2005/05/identity/claims:EmailAddress" AndAlso myClaim.Right = Rights.PossessProperty Then
            Dim emailAddress = TryCast(myClaim.Resource, String)
            If emailAddress Is Nothing Then
                Return False
            End If
            If Not IsValidEmailAddress(emailAddress) Then
                Return False
            End If
            Return True
        Else
            Return False
        End If
    End Function

    ' This helper method performs a rudimentary check for whether 
    'a given email is valid.
    Private Shared Function IsValidEmailAddress(ByVal emailAddress As String) As Boolean
        Dim splitEmail() = emailAddress.Split("@"c)
        If splitEmail.Length <> 2 Then
            Return False
        End If
        If Not splitEmail(1).Contains(".") Then
            Return False
        End If
        Return True
    End Function
End Class

액세스가 true이면 STS A는 userAuthenticated 클레임과 함께 SAML 토큰을 발급합니다.

// Create the list of SAML Attributes.
List<SamlAttribute> samlAttributes = new List<SamlAttribute>();
// Add the userAuthenticated claim.
List<string> strList = new List<string>();
strList.Add("true");
SamlAttribute mySamlAttribute = new SamlAttribute("http://www.tmpuri.org",
     "userAuthenticated", strList);
samlAttributes.Add(mySamlAttribute);
// Create the SAML token with the userAuthenticated claim. It is assumed that
// the method CreateSamlToken() is implemented as part of STS-A.
SamlSecurityToken samlToken = CreateSamlToken(
    proofToken,
    issuerToken,
    samlConditions,
    samlSubjectNameFormat,
    samlSubjectEmailAddress,
    samlAttributes);
' Create the list of SAML Attributes.
Dim samlAttributes As New List(Of SamlAttribute)()
' Add the userAuthenticated claim.
Dim strList As New List(Of String)()
strList.Add("true")
Dim mySamlAttribute As New SamlAttribute("http://www.tmpuri.org", _
                                         "userAuthenticated", _
                                         strList)
samlAttributes.Add(mySamlAttribute)
' Create the SAML token with the userAuthenticated claim. It is assumed that 
' the method CreateSamlToken() is implemented as part of STS-A.
Dim samlToken = CreateSamlToken(proofToken, issuerToken, samlConditions, _
                                samlSubjectNameFormat, _
                                samlSubjectEmailAddress, _
                                samlAttributes)

조직 A의 클라이언트

다음 그림에서는 MyService 서비스 호출에 포함된 단계와 함께 조직 A의 클라이언트를 보여 줍니다. 다른 기능 구성 요소도 완전성을 위해 포함됩니다.

Diagram showing the steps in a MyService service call.

요약

페더레이션 보안은 책임을 확실히 나누며, 안전하고 확장성 있는 서비스 아키텍처를 구축하는 데 도움이 됩니다. WCF는 분산 애플리케이션을 빌드하고 배포하기 위한 플랫폼으로서, 페더레이션 보안을 구현하기 위한 기본적인 지원을 제공합니다.

참고 항목