Share via


方法 : カスタム セキュリティ トークン認証システムを作成する

ここでは、カスタム セキュリティ トークン認証システムの作成方法と、これをカスタム セキュリティ トークン マネージャーに統合する方法を示します。 セキュリティ トークン認証システムは受信メッセージと共に提出されるセキュリティ トークンの内容を検証します。 検証に成功すると、認証システムは IAuthorizationPolicy インスタンスのコレクションを返します。これが評価されるとクレーム セットが返されます。

Windows Communication Foundation (WCF) でカスタム セキュリティ トークン認証システムを使用するには、カスタム資格情報と、セキュリティ トークン マネージャーの実装を作成する必要があります。 カスタム資格情報とセキュリティ トークン マネージャーの作成の詳細については、「チュートリアル: カスタム クライアントおよびサービスの資格情報を作成する」を参照してください。

手順

カスタム セキュリティ トークン認証システムを作成するには

  1. SecurityTokenAuthenticator クラスから派生する新しいクラスを定義します。

  2. CanValidateTokenCore メソッドをオーバーライドします。 カスタム認証システムが受信トークンの種類を検証できるかどうかによって、メソッドから true または false が返されます。

  3. ValidateTokenCore メソッドをオーバーライドします。 このメソッドでは、トークンの内容を適切に検証する必要があります。 トークンが検証手順をパスすると、IAuthorizationPolicy インスタンスのコレクションが返されます。 下記の例では、次の手順で作成するカスタム承認ポリシーの実装を使用します。

    internal class MySecurityTokenAuthenticator : SecurityTokenAuthenticator
    {
        protected override bool CanValidateTokenCore(SecurityToken token)
        {
            // Check that the incoming token is a username token type that
            // can be validated by this implementation.
            return (token is UserNameSecurityToken);
        }
    
        protected override ReadOnlyCollection<IAuthorizationPolicy>
            ValidateTokenCore(SecurityToken token)
        {
            UserNameSecurityToken userNameToken = token as UserNameSecurityToken;
    
            // Validate the information contained in the username token. For demonstration
            // purposes, this code just checks that the user name matches the password.
            if (userNameToken.UserName != userNameToken.Password)
            {
                throw new SecurityTokenValidationException("Invalid user name or password");
            }
    
            // Create just one Claim instance for the username token - the name of the user.
            DefaultClaimSet userNameClaimSet = new DefaultClaimSet(
                ClaimSet.System,
                new Claim(ClaimTypes.Name, userNameToken.UserName, Rights.PossessProperty));
            List<IAuthorizationPolicy> policies = new List<IAuthorizationPolicy>(1);
            policies.Add(new MyAuthorizationPolicy(userNameClaimSet));
            return policies.AsReadOnly();
        }
    }
    
    Friend Class MySecurityTokenAuthenticator
        Inherits SecurityTokenAuthenticator
    
        Protected Overrides Function CanValidateTokenCore(ByVal token As SecurityToken) As Boolean
            ' Check that the incoming token is a username token type that  
            ' can be validated by this implementation.
            Return (TypeOf token Is UserNameSecurityToken)
        End Function
    
        Protected Overrides Function ValidateTokenCore(ByVal token As SecurityToken) As ReadOnlyCollection(Of IAuthorizationPolicy)
    
            Dim userNameToken = TryCast(token, UserNameSecurityToken)
    
            ' Validate the information contained in the username token. For demonstration 
            ' purposes, this code just checks that the user name matches the password.
            If userNameToken.UserName <> userNameToken.Password Then
                Throw New SecurityTokenValidationException("Invalid user name or password")
            End If
    
            ' Create just one Claim instance for the username token - the name of the user.
            Dim userNameClaimSet As New DefaultClaimSet(ClaimSet.System, _
                                                        New Claim(ClaimTypes.Name, _
                                                        userNameToken.UserName, _
                                                        Rights.PossessProperty))
            Dim policies As New List(Of IAuthorizationPolicy)(1)
            policies.Add(New MyAuthorizationPolicy(userNameClaimSet))
            Return policies.AsReadOnly()
        End Function
    
    End Class
    

上記のコードでは、CanValidateToken(SecurityToken) メソッドに承認ポリシーのコレクションが返されます。 WCF には、このインターフェイスのパブリックな実装は用意されていません。 以下の手順では、これを独自の要件について実行する方法を示します。

カスタム承認ポリシーを作成するには

  1. IAuthorizationPolicy インターフェイスを実装する新しいクラスを定義します。

  2. Id の読み取り専用プロパティを実装します。 このプロパティを実装する方法の 1 つは、クラスのコンストラクターでグローバル一意識別子 (GUID) を生成し、この値をプロパティの値が求められるたびに返すことです。

  3. Issuer の読み取り専用プロパティを実装します。 このプロパティは、トークンから取得されるクレーム セットの発行者を返す必要があります。 この発行者は、トークンの発行者、またはトークンの内容を検証する証明機関に対応している必要があります。 次の例では、前の手順で作成したカスタム セキュリティ トークン認証システムから、このクラスに渡された発行者クレームを使用します。 カスタム セキュリティ トークン認証システムでは、(System プロパティから返される) システム提供のクレーム セットを使用して、ユーザー名トークンの発行者を表します。

  4. Evaluate メソッドを実装します。 このメソッドは (引数として渡される) EvaluationContext クラスのインスタンスに、受信セキュリティ トークンの内容に基づいたクレームを設定します。 評価が完了したら、メソッドは true を返します。 実装が、評価コンテキストに追加情報を提供する他の承認ポリシーの存在に依存している場合、必要な情報が評価コンテキスト内に存在していないと、このメソッドは false を返します。 この場合、承認ポリシーによって評価コンテキストが 1 つでも変更されていると、この受信メッセージのために生成された他のすべての承認ポリシー評価の終了後に、WCF は、このメソッドを再び呼び出します。

    internal class MyAuthorizationPolicy : IAuthorizationPolicy
    {
        string id;
        ClaimSet tokenClaims;
        ClaimSet issuer;
    
        public MyAuthorizationPolicy(ClaimSet tokenClaims)
        {
            if (tokenClaims == null)
            {
                throw new ArgumentNullException("tokenClaims");
            }
            this.issuer = tokenClaims.Issuer;
            this.tokenClaims = tokenClaims;
            this.id = Guid.NewGuid().ToString();
        }
    
        public ClaimSet Issuer
        {
            get { return issuer; }
        }
    
        public string Id
        {
            get { return id; }
        }
    
        public bool Evaluate(EvaluationContext evaluationContext, ref object state)
        {
            // Add the token claim set to the evaluation context.
            evaluationContext.AddClaimSet(this, tokenClaims);
    
            // Return true if the policy evaluation is finished.
            return true;
        }
    }
    
    Friend Class MyAuthorizationPolicy
        Implements IAuthorizationPolicy
    
        Private _id As String
        Private _tokenClaims As ClaimSet
        Private _issuer As ClaimSet
    
        Public Sub New(ByVal tokenClaims As ClaimSet)
            If _tokenClaims Is Nothing Then
                Throw New ArgumentNullException("tokenClaims")
            End If
            Me._issuer = tokenClaims.Issuer
            Me._tokenClaims = tokenClaims
            Me._id = Guid.NewGuid().ToString()
        End Sub
    
        Public ReadOnly Property Issuer() As ClaimSet Implements IAuthorizationPolicy.Issuer
            Get
                Return _issuer
            End Get
        End Property
    
        Public ReadOnly Property Id() As String Implements System.IdentityModel.Policy.IAuthorizationComponent.Id
            Get
                Return _id
            End Get
        End Property
    
        Public Function Evaluate(ByVal evaluationContext As EvaluationContext, _
                                 ByRef state As Object) As Boolean Implements IAuthorizationPolicy.Evaluate
    
            ' Add the token claim set to the evaluation context.
            evaluationContext.AddClaimSet(Me, _tokenClaims)
            ' Return true if the policy evaluation is finished.
            Return True
        End Function
    
    End Class
    

チュートリアル: カスタム クライアントおよびサービスの資格情報の作成」では、カスタム資格情報とカスタム セキュリティ トークン マネージャーを作成する方法について説明しています。 ここで作成したカスタム セキュリティ トークン認証システムを使用するには、CreateSecurityTokenAuthenticator メソッドからカスタム認証システムを返すようにセキュリティ トークン マネージャーの実装を変更します。 適切なセキュリティ トークン要件が渡されると、このメソッドは認証システムを返します。

カスタム セキュリティ トークン マネージャーにカスタム セキュリティ トークン認証システムを統合するには

  1. カスタム セキュリティ トークン マネージャーの実装の CreateSecurityTokenAuthenticator メソッドをオーバーライドします。

  2. SecurityTokenRequirement パラメーターに基づいてカスタム セキュリティ トークン認証システムを返すロジックをメソッドに追加します。 次の例では、トークン要件のトークンの種類が (UserName プロパティで表される) ユーザー名で、セキュリティ トークン認証システムで要求されているメッセージの方向 (Input フィールドで表される) が入力である場合、カスタム セキュリティ トークン認証システムが返されます。

    internal class MyServiceCredentialsSecurityTokenManager :
        ServiceCredentialsSecurityTokenManager
    {
        ServiceCredentials credentials;
        public MyServiceCredentialsSecurityTokenManager(ServiceCredentials credentials)
            : base(credentials)
        {
            this.credentials = credentials;
        }
    
        public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator
            (SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
        {
            // Return your implementation of the SecurityTokenProvider based on the
            // tokenRequirement argument.
            SecurityTokenAuthenticator result;
            if (tokenRequirement.TokenType == SecurityTokenTypes.UserName)
            {
                MessageDirection direction = tokenRequirement.GetProperty<MessageDirection>
                    (ServiceModelSecurityTokenRequirement.MessageDirectionProperty);
                if (direction == MessageDirection.Input)
                {
                    outOfBandTokenResolver = null;
                    result = new MySecurityTokenAuthenticator();
                }
                else
                {
                    result = base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
                }
            }
            else
            {
                result = base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
            }
    
            return result;
        }
    }
    
    Friend Class MyServiceCredentialsSecurityTokenManager
        Inherits ServiceCredentialsSecurityTokenManager
    
        Private credentials As ServiceCredentials
    
        Public Sub New(ByVal credentials As ServiceCredentials)
            MyBase.New(credentials)
            Me.credentials = credentials
        End Sub
    
        Public Overrides Function CreateSecurityTokenAuthenticator(ByVal tokenRequirement As SecurityTokenRequirement, _
                                                                   <System.Runtime.InteropServices.Out()> _
                                                                   ByRef outOfBandTokenResolver _
                                                                   As SecurityTokenResolver) As SecurityTokenAuthenticator
            ' Return your implementation of the SecurityTokenProvider based on the 
            ' tokenRequirement argument.
            Dim result As SecurityTokenAuthenticator
            If tokenRequirement.TokenType = SecurityTokenTypes.UserName Then
                Dim direction = tokenRequirement.GetProperty(Of MessageDirection)(ServiceModelSecurityTokenRequirement.MessageDirectionProperty)
                If direction = MessageDirection.Input Then
                    outOfBandTokenResolver = Nothing
                    result = New MySecurityTokenAuthenticator()
                Else
                    result = MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, _
                                                                     outOfBandTokenResolver)
                End If
            Else
                result = MyBase.CreateSecurityTokenAuthenticator(tokenRequirement, _
                                                                 outOfBandTokenResolver)
            End If
    
            Return result
        End Function
    
    End Class
    

関連項目