web-dev-qa-db-ja.com

カスタムClientCredentialsを使用したWCF認証:使用するclientCredentialTypeは何ですか?

基本的なWCFUserName/Pwdセキュリティを廃止し、独自のカスタムクライアント資格情報を実装して、デフォルトで提供される情報以外の情報を保持する必要がありました。

私は このMSDNの記事 を試しましたが、機能しないために何かが足りません。

まず、カスタムClientCredentialsSecurityTokenManagerを提供するカスタムClientCredentialsがいくつかあります。

public class CentralAuthCredentials : ClientCredentials
{
    public override System.IdentityModel.Selectors.SecurityTokenManager CreateSecurityTokenManager()
    {
        return new CentralAuthTokenManager(this);
    }
}

public class CentralAuthTokenManager : ClientCredentialsSecurityTokenManager
{
    private CentralAuthCredentials credentials;

    public CentralAuthTokenManager(CentralAuthCredentials creds) : base(creds)
    {
        this.credentials = creds;
    }

    public override SecurityTokenProvider CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
    {
        if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE)
            return new CentralAuthTokenProvider(credentials.UserId, credentials.UserPassword, credentials.ImpersonateId, credentials.LoginType);
        else
            return base.CreateSecurityTokenProvider(tokenRequirement);
    }

    public override SecurityTokenAuthenticator CreateSecurityTokenAuthenticator(SecurityTokenRequirement tokenRequirement, out SecurityTokenResolver outOfBandTokenResolver)
    {
        outOfBandTokenResolver = null;
        if (this.IsIssuedSecurityTokenRequirement(tokenRequirement) || tokenRequirement.TokenType == CentralAuthToken.TOKEN_TYPE)
            return new CentralAuthTokenAuthenticator();
        else
            return base.CreateSecurityTokenAuthenticator(tokenRequirement, out outOfBandTokenResolver);
    }

    public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
    {
        return new CentralAuthTokenSerializer();
    }
}

これで、アプリを実行すると、カスタム資格情報とトークンマネージャーが作成されます。ただし、メソッドでは:

CreateSecurityTokenProvider(SecurityTokenRequirement tokenRequirement)
{
    ...
}

TokenRequirement.TokenTypeは、私のカスタムトークン以外のものとして出くわします。それは私の最初の質問をもたらします:WCFはトークンの要件が何であるかをどうやって知っていますか?

また、方法:

public override SecurityTokenSerializer CreateSecurityTokenSerializer(SecurityTokenVersion version)
{
    return new CentralAuthTokenSerializer();
}

クライアントによって一度呼び出されますが、返されたトークンシリアライザーのどのメソッドも呼び出されません。これは、カスタムトークンがネットワークを介して送信されていないことを示しています。これは、CreateSecurityTokenProvider()を呼び出しても、カスタムトークンプロバイダーが返されないためだと思います。これは、カスタムトークンが必要であることを示すSecurityTokenRequirementが渡されないためです。

クライアント側では、私は持っています:

public class CentralAuthorizationManagerClient : ClientBase<ICentralAuthorizationManager>, ICentralAuthorizationManager, IDisposable
{
    public PFPrincipal GenerateToken()
    {
        if (!this.ChannelFactory.Endpoint.Behaviors.Contains(typeof(CentralAuthCredentials)))
            throw new ArgumentException("Must set CentralAuthCredentials before calling this method.");
        return base.Channel.GenerateToken();
    }

    public PFPrincipal GenerateToken(CentralAuthToken token)
    {
        this.ChannelFactory.Endpoint.Behaviors.Remove<ClientCredentials>();
        this.ChannelFactory.Endpoint.Behaviors.Add(new CentralAuthCredentials(token));
        return this.GenerateToken();
    }

これらのメソッドは基本的に、エンドポイントからデフォルトの資格情報を削除し、カスタムCentralAuthCredentialsの新しいインスタンスをアタッチすることになっています。 (MSDNの記事からこの削除/追加コンボをどこかで入手しました)。

構成内:

    <behaviors>
        <endpointBehaviors>
            <behavior name="Server2ServerEndpointBehavior">
                <clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">
                    <clientCertificate findValue="localhost" x509FindType="FindBySubjectName" storeLocation="CurrentUser" storeName="My" />
                    <serviceCertificate>
                        <authentication certificateValidationMode="None" revocationMode="NoCheck" />
                    </serviceCertificate>
                </clientCredentials>
            </behavior>
        </endpointBehaviors>
    </behaviors>

    <bindings>
        <wsHttpBinding>
            <binding name="wsHttpServer2Server">
                <security mode="Message">
                    <message clientCredentialType="UserName" />
                </security>
            </binding>
        </wsHttpBinding>
    </bindings>

ビヘイビアのclientCredentialsタイプがカスタムクライアント資格情報に設定されていることに注意してください。ただし、現時点では、バインディングのclientCredentialTypeを「UserName」に設定しています。これは私の2番目の質問をもたらします:clientCredentialType = "は一体何をすべきですか?"カスタム資格情報を使用している場合はに設定されますか? MSDNによると、メッセージセキュリティに使用できる値は次のとおりです。なしWindowsUserNameCertificate、およびIssuedToken

何か案は?うまくいけば、私は単純なものが欠けているだけですか?実装全体にさらに6つのクラスがありますが、状況を理解するために必要なビットのみを含めようとしました...


更新#1:

私は一日中これに取り組んできました、そしていくつかの情報源のおかげで、私が欠けていたものの一部が このページ の最後のステップであることに気付きました。それはバインディングにTokenParametersを追加しています、そのため、バインディングはトークンがどのように見えるかを認識します。それが私の最初の最初の質問に対する答えです。 「一体何がトークン要件を設定しますか?」回答:バインディングに割り当てられたTokenParameters。

そこで、バインディングにTokenParametersを設定する次の拡張機能を追加しました。

public sealed class CentralAuthTokenBindingExtension : BindingElementExtensionElement
{
    public CentralAuthTokenBindingExtension()
        : base()
    {
    }

    public override Type BindingElementType
    {
        get { return typeof(SymmetricSecurityBindingElement); }
    }

    protected override System.ServiceModel.Channels.BindingElement CreateBindingElement()
    {
        X509SecurityTokenParameters protectionParams = new X509SecurityTokenParameters();
        protectionParams.InclusionMode = SecurityTokenInclusionMode.Never;

        SymmetricSecurityBindingElement innerBindingElement = new SymmetricSecurityBindingElement();
        innerBindingElement.EndpointSupportingTokenParameters.SignedEncrypted.Add(new CentralAuthTokenParameters());
        //innerBindingElement.MessageProtectionOrder = MessageProtectionOrder.SignBeforeEncrypt;
        innerBindingElement.ProtectionTokenParameters = protectionParams;

        return innerBindingElement;
    }
}

    <extensions>
        <bindingElementExtensions>
            <add name="CentralAuthCreds" type="MyApp.Security.Configuration.CentralAuthTokenBindingExtension, MyApp, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null" />
        </bindingElementExtensions>
    </extensions>

    <bindings>
        <customBinding>
            <binding name="wsHttpServer2Server">
                <CentralAuthCreds />
                <binaryMessageEncoding />
                <httpTransport />
            </binding>
        </customBinding>
    </bindings>

さて、それは私をさらに一歩進めます。サーバーで新しい例外が発生しました。

"The security token manager cannot create a token authenticator for requirement ..."

WCFは、カスタムトークンハンドラーではなく、デフォルトのトークンマネージャーを使用してカスタムトークンを処理しようとしているようです(カスタムトークンハンドラーのコンストラクターは呼び出されません)。私はthinkこれが起こっているのは、clientの場合、次の設定があるためです。

<endpointBehaviors>
    <behavior name="Server2ServerEndpointBehavior">
        <clientCredentials type="MyApp.Security.CentralAuthCredentials, MyApp">

しかし、サーバーには、カスタムクライアントの資格情報について通知するのに相当するものがありません。したがって、新しい質問:サーバーの構成のどこにカスタムClientCredentialsが何であるかを伝えますか?


更新#2:

さて、私はついにパズルのもう少しを理解しました。私はClientCredentialsの実装を実装しただけで、クライアントがcredsを送信すると考えていました。それだけです。クライアントはサービスを認証しないため、カスタムServiceCredentialsは必要ありません。まあ、私は間違っていました。指定されたServiceCredentialsは、ClientCredentialsからトークンを認証します。その逆も同様です。そのため、同じTokenSerializerクラスとTokenAuthenticatorクラスを渡すカスタムServiceCredentials実装を追加する必要がありました。

次の問題へ:WCFは、ユーザー名認証で正常に機能していた、構成で指定されたx509証明書を無視するようになりました。これについてはまったく新しい質問を開きます。

25
CodingWithSpike

作業中のアプリケーションで同様の問題が発生しましたが、カスタム資格情報を機能させることができなかったため、残念ながらあきらめました。現在、ユーザー名/パスワード(クライアント資格情報)と証明書(サービス資格情報)を使用しており、カスタム暗号化されたSOAPヘッダーがサービス呼び出しに追加されて、ユーザーIDなどの追加情報を渡します。

1
Tanner