none
WCF TCPアクセスでの外部端末からの接続 RRS feed

  • 質問

  • お世話になっております。
    掲題に関して質問させてください。

    現在、WCFのアプリを作成しており、自端末での連携確認はできました。
    問題なのは、外部端末からの接続でエラーが発生してしまうことです。

    エラー種類:SecurityNegotiationException
    メッセージ:サーバーは、クライアントの資格情報を拒否しました。

    OSはWin7(サーバ)とWindowsServer2008(クライアント)です。
    いずれもファイアウォール・セキュリティソフトを止めてのアクセスも試してみました。
    他に必要な設定があれば教えて頂けないでしょうか。
    (セキュリティの設定が必要なのでしょうか)

    以下、configの設定値

    ===サーバ===
    <?xml version="1.0" encoding="utf-8" ?>

    <configuration>
        <system.serviceModel>
            <behaviors />
            <services>
                <service name="WcfServiceLibrary1.OrderService">
                    <endpoint address="net.tcp://********:****/OrderService/" binding="netTcpBinding"
                        bindingConfiguration="" contract="WcfServiceLibrary1.IOrderService" />
                </service>
            </services>
        </system.serviceModel>
    </configuration>


    ===クライアント===

        <system.serviceModel>
            <client>
                <endpoint address="net.tcp://*********:****/OrderService/" binding="netTcpBinding"
                    bindingConfiguration="" contract="WcfServiceLibrary1.IOrderService"
                    name="EndpointTCP" />
            </client>
        </system.serviceModel>

    ===クライアント接続処理(cs)===

    using (ChannelFactory<WcfServiceLibrary1.IOrderService> factory = new ChannelFactory<WcfServiceLibrary1.IOrderService>("EndpointTCP"))
    {
    // ChannelFactory のオープン 
    factory.Open();
    WcfServiceLibrary1.IOrderService proxy = factory.CreateChannel();
    // メソッドの呼び出し 
    WcfServiceLibrary1.OrderItem item = proxy.GetOrderById(3);
    // ChannelFactory のクローズ 
    factory.Close();

    ※WcfServiceLibrary1.OrderItem item = proxy.GetOrderById(3); でエラーが発生
    そもそも、接続方法もこれで正しいのでしょうか。

    ◆参考サイト
    ・Windows Communication Foundation (WCF)
    http://msdn.microsoft.com/ja-jp/netframework/aa663324.aspx

    上記サイトの「10行でズバリ」の手順を基に開発途中です。(サービスもサンプル同様。)
    異なるのはHTTPかTCPかくらいだと思われます。

    2012年7月19日 2:09

回答

すべての返信

  • こんにちは。

    これかな・・・http://msdn.microsoft.com/ja-jp/library/ms731316

    既定値はトランスポートですね。

    • 編集済み Keiichi Oumi 2012年7月19日 2:34
    • 回答としてマーク kaijin22 2012年7月24日 5:51
    2012年7月19日 2:32
  • Keiichi Oumi様

    ご指摘ありがとうございます。
    サイトを頼りに調べてみたところ、bindingConfigurationでセキュリティが設定できることが分かりました。
    そのセキュリティ設定をNoneに設定したところ、外部端末から問題なくつなげることができました。ありがとうございました。

    合わせて質問させてください。
    そもそもWCFのセキュリティの用途を理解しきれていないのですが、TCP通信でもセキュリティを設定した方が良いと考えています。
    (サービス自体は外部公開しませんが、アクセスするサイトは外部公開しているので)

    セキュリティ設定時のサンプルサイトなどあれば、教えて頂けないでしょうか。
    2012年7月19日 5:11
  • こんにちは。

    どのようなセキュリティを必要とするかっていう見当は、別途行うものとして。

    サンプル等ということであれば、

    Windows Communication Foundation セキュリティ
    http://msdn.microsoft.com/ja-jp/library/ms732362

    ここを中心に読み込んで、


    一般的なセキュリティ シナリオ
    http://msdn.microsoft.com/ja-jp/library/ms730301

    ここらあたりを読むと、サンプルは色々そろっていますよぅ。

    2012年7月19日 9:04
  • Keiichi Oumi様

    ご連絡ありがとうございます。ひとまず返信させていただきました。
    現在頂いたサイトを読んでいる途中です。
    (理解できていない
    用語が多いので、まだ斜め読みに近いですが)

    また、度々申し訳ないのですが、追加で質問させてください。

    どのようなセキュリティを必要とするかっていう見当は、別途行うものとして。

    頂いたコメントは、システムに対してどのようなセキュリティ設定を行うべきか。のお話だと思っています。
    ひとまず、デフォルトのトランスポートモードで連携できればよいと考えているのですが、

    ・デフォルト設定だとしても、上記のようなconfigのみの設定だけではなく、証明書(サービス)を介する必要があるのでしょうか。

    ・また、デフォルト設定の場合、以下サイトが近いと考えているのですが正しいでしょうか。
    (TCP通信+デフォルト(トランスポート)設定)
    (利用すると認証エラーが発生するので、Windows認証の為に何か設定が必要?

    ・トランスポート セキュリティと Windows 認証
    http://msdn.microsoft.com/ja-jp/library/ms733089

    2012年7月19日 11:02
  • 前提条件が漏れていたのですが、今回IISは利用しません。
    (コンソールを常駐させ、アクセスさせるような動作を想定しています。
    そもそも内部ネットワークで完結させるサービスの為、外のネットワークに出ることはありません)

    IIS利用しない場合、Windows認証はできない認識でよろしいのでしょうか。

    ・10 行でズバリ!! [C#] WCF サービスにおける基本認証
    http://code.msdn.microsoft.com/10-C-WCF-be474bca


    • 編集済み kaijin22 2012年7月20日 1:02
    2012年7月20日 0:16
  • ・デフォルト設定だとしても、上記のようなconfigのみの設定だけではなく、証明書(サービス)を介する必要があるのでしょうか。

    clientCredentialTypeが、WindowsかCertificateかの違いだと思います。
    Certificateであれば、証明書が必要となりますね。

    ・また、デフォルト設定の場合、以下サイトが近いと考えているのですが正しいでしょうか。
     (TCP通信+デフォルト(トランスポート)設定)
     (利用すると認証エラーが発生するので、Windows認証の為に何か設定が必要?

    ・トランスポート セキュリティと Windows 認証
    http://msdn.microsoft.com/ja-jp/library/ms733089

    そうですね、これが近いと思います。
    認証エラーは、エラーの内容を見ない事にはなんとも・・・

    2012年7月20日 1:14
  • こんにちは。

    記憶が、WCF登場した当時のものなので(^^;
    当時作成したドキュメントを見ながらちょっとやってみました。

    特に、何も考えずに作りましたが、動いています。パケットの中身までは見ていませんが、クライアント側のセキュリティモードをNoneなどに変更すると、接続できなくなる(Exceptino)ので、一応は、動作していると思います。

    環境的に何かあるかなーと考えても、AD立ててドメインに参加しているくらいで、普通ですね。

     

    2台のPCを使い、
    wsHttpBinding <security mode="None" />
    netTcpBinding <security mode="None" />
    netTcpBinding <security mode="Transport" />

    と3パターンをやってみました。

    SelfHost用のコードは、いい加減ですが・・・

    ------------------------------------------------------------------------------

    Public Class MyService
        Implements IMyService

        Public Function MyOperation1() As String Implements IMyService.MyOperation1
            Return "Datetime : " + DateTime.Now.ToString
        End Function


        Public Shared Sub Main()

            'Try
            Using serviceHost As New System.ServiceModel.ServiceHost(GetType(MyService))

                '// ServiceHostをOpenし、メッセージのリスニングを開始
                serviceHost.Open()

                Console.WriteLine(serviceHost.BaseAddresses.Item(0).OriginalString)

                Console.WriteLine("The service is ready.")
                Console.WriteLine("Press <ENTER> to terminate service.")
                Console.ReadLine()
                '// ServiceHostをCloseし、サービスをシャットダウン
                serviceHost.Close()
            End Using
           
        End Sub

    End Class

    <ServiceContract([namespace]:="http://localhost/MyService")> _
    Public Interface IMyService

        <OperationContract()> _
        Function MyOperation1() As String

    End Interface

    ------------------------------------------------------------------------------

    ホストアプリのApp.Configは、最終的に以下の感じ、微調整など何もしていない状態です(^^;;;
    作りも結構適当です・・・

      <system.serviceModel>
        <bindings>
          <netTcpBinding>
            <binding name="NewBinding0">
              <security mode="Transport" />
            </binding>
          </netTcpBinding>
        </bindings>
        <services>
          <service behaviorConfiguration="returnFaults" name="SelfHost.MyService">
            <endpoint binding="netTcpBinding" bindingConfiguration="NewBinding0"
              name="ServiceMethod1" contract="SelfHost.IMyService" />
            <host>
              <baseAddresses>
                <add baseAddress="http://localhost/MyService" />
                <add baseAddress="net.tcp://localhost/MyService" />
              </baseAddresses>
            </host>
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="returnFaults">
              <serviceMetadata httpGetEnabled="true" httpGetUrl="" />
              <serviceDebug includeExceptionDetailInFaults="false" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
       
      </system.serviceModel>

     

    クライアントアプリは、ボタンが1個あるだけの簡単なもので、
    App.Configは、以下の通り、WSDL参照で作ったもので、特にいじっていません。


    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <startup>
            <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0,Profile=Client" />
        </startup>
        <system.serviceModel>
            <bindings>
                <netTcpBinding>
                    <binding name="ServiceMethod1" closeTimeout="00:01:00" openTimeout="00:01:00"
                        receiveTimeout="00:10:00" sendTimeout="00:01:00" transactionFlow="false"
                        transferMode="Buffered" transactionProtocol="OleTransactions"
                        hostNameComparisonMode="StrongWildcard" listenBacklog="10"
                        maxBufferPoolSize="524288" maxBufferSize="65536" maxConnections="10"
                        maxReceivedMessageSize="65536">
                        <readerQuotas maxDepth="32" maxStringContentLength="8192" maxArrayLength="16384"
                            maxBytesPerRead="4096" maxNameTableCharCount="16384" />
                        <reliableSession ordered="true" inactivityTimeout="00:10:00"
                            enabled="false" />
                        <security mode="Transport">
                            <transport clientCredentialType="Windows" protectionLevel="EncryptAndSign" />
                            <message clientCredentialType="Windows" />
                        </security>
                    </binding>
                </netTcpBinding>
            </bindings>
            <client>
                <endpoint address="net.tcp://接続先コンピュータ名/MyService" binding="netTcpBinding"
                    bindingConfiguration="ServiceMethod1" contract="ServiceReference1.IMyService"
                    name="ServiceMethod1">
                    <identity>
                        <userPrincipalName value="メールアドレス" />
                    </identity>
                </endpoint>
            </client>
        </system.serviceModel>
    </configuration>

     

    2012年7月20日 2:29
  • Keiichi Oumi様

    ご連絡ありがとうございます。
    Windows認証(統合Windows認証)を調べていくと、以下のようなサイトがありました。
    今回作成するのは、コンソールでのサービスであり、IISからホストしません。
    認証を行う場合、IISからホストする必要があるのでしょうか。

    統合Windows認証【Windows authentication】http://e-words.jp/w/E7B5B1E59088WindowsE8AA8DE8A8BC.html

    Windows認証を実装したWebアプリケーション
    http://www.atmarkit.co.jp/fdotnet/aspnet/aspnet18/aspnet18_01.html


    また、以下がエラーメッセージになります。

    イベント:ボタン押下により、サービスを起動
    エラーメッセージ:
    サーバーは、クライアントの資格情報を拒否しました。
    スタックトレース:

    Server stack trace: 
       場所 System.ServiceModel.Channels.WindowsStreamSecurityUpgradeProvider.WindowsStreamSecurityUpgradeInitiator.OnInitiateUpgrade(Stream stream, SecurityMessageProperty& remoteSecurity)
       場所 System.ServiceModel.Channels.StreamSecurityUpgradeInitiatorBase.InitiateUpgrade(Stream stream)
       場所 System.ServiceModel.Channels.ConnectionUpgradeHelper.InitiateUpgrade(StreamUpgradeInitiator upgradeInitiator, IConnection& connection, ClientFramingDecoder decoder, IDefaultCommunicationTimeouts defaultTimeouts, TimeoutHelper& timeoutHelper)
       場所 System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.SendPreamble(IConnection connection, ArraySegment`1 preamble, TimeoutHelper& timeoutHelper)
       場所 System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.DuplexConnectionPoolHelper.AcceptPooledConnection(IConnection connection, TimeoutHelper& timeoutHelper)
       場所 System.ServiceModel.Channels.ConnectionPoolHelper.EstablishConnection(TimeSpan timeout)
       場所 System.ServiceModel.Channels.ClientFramingDuplexSessionChannel.OnOpen(TimeSpan timeout)
       場所 System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
       場所 System.ServiceModel.Channels.ServiceChannel.OnOpen(TimeSpan timeout)
       場所 System.ServiceModel.Channels.CommunicationObject.Open(TimeSpan timeout)
       場所 System.ServiceModel.Channels.ServiceChannel.CallOpenOnce.System.ServiceModel.Channels.ServiceChannel.ICallOnce.Call(ServiceChannel channel, TimeSpan timeout)
       場所 System.ServiceModel.Channels.ServiceChannel.CallOnceManager.CallOnce(TimeSpan timeout, CallOnceManager cascade)
       場所 System.ServiceModel.Channels.ServiceChannel.EnsureOpened(TimeSpan timeout)
       場所 System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs, TimeSpan timeout)
       場所 System.ServiceModel.Channels.ServiceChannel.Call(String action, Boolean oneway, ProxyOperationRuntime operation, Object[] ins, Object[] outs)
       場所 System.ServiceModel.Channels.ServiceChannelProxy.InvokeService(IMethodCallMessage methodCall, ProxyOperationRuntime operation)
       場所 System.ServiceModel.Channels.ServiceChannelProxy.Invoke(IMessage message)


    ===利用config(サービス)===

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
        <system.serviceModel>
          <bindings>
            <netTcpBinding>
              <binding name="EndpointTCP">
                <security mode="Transport">
                  <transport clientCredentialType="Windows"/>
                </security>
              </binding>
            </netTcpBinding>
          </bindings>
            <behaviors />
            <services>
                <service name="WcfServiceLibrary1.OrderService">
                    <endpoint address="net.tcp://********:****/OrderService/" binding="netTcpBinding" name="EndpointTCP"
                        bindingConfiguration="EndpointTCP" contract="WcfServiceLibrary1.IOrderService">
                  </endpoint>
                </service>
            </services>
        </system.serviceModel>
    </configuration>

    ===利用config(クライアント)===

      <system.serviceModel>
        <bindings>
          <netTcpBinding>
            <binding name="TcpConfig" >
              <security mode="Transport">
                <transport clientCredentialType="Windows"/>
              </security>
            </binding>
          </netTcpBinding>
        </bindings>
        <client>
          <endpoint address="net.tcp://********:****/OrderService/" binding="netTcpBinding"
              bindingConfiguration="TcpConfig" contract="WcfServiceLibrary1.IOrderService"
              name="EndpointTCP">
          </endpoint>
        </client>
      </system.serviceModel>

    ※Webサービスをコンソール起動(常駐)

    2012年7月20日 2:35
  • わたしが試したのも SelfHost つまり、コンソールアプリなのですが・・・
    2012年7月20日 3:04
  • こんにちは。

    「認証」をどのようなものだと考えていらっしゃるでしょうか?

    ・トランスポート セキュリティと Windows 認証
    http://msdn.microsoft.com/ja-jp/library/ms733089

    この考え方でいくと、WCFでの認証行為は、ログインした情報(認証チケット)で、WCFが自動的に(トランスポートレベルで)認証を行うと読めるのですが、何か特別なことをやろうとしていますか?

    2012年7月20日 3:18
  • >「認証」をどのようなものだと考えていらっしゃるでしょうか?
    アクセスを許可しているクライアントのみがアクセス可能とするための機能。みたいな認識です。
    今回の話では、メッセージ・結果の改ざんなどが含まれていると考えています。

    主なモードが、トランスポートモードと、メッセージモード(+混在)の2種類で設定可能

    ==========
    ログインした情報(認証チケット)で、

    とありますが、WebサービスにアクセスしているWebサイトは、特にログインしていません。
    何か認証チケットを発行するような処理がWebサイト側にも必要なのでしょうか。
    (VisualStudioのデバッグ実行でも、Windowsのユーザが利用されていると思っていました)

    疑問なのは、何と認証(突き合わせ)を行うのかがよくわかっていません。
    Windowsのユーザ情報を元に認証を行うとしても、誰が正かの判断をだれが・どこで。やるのかがわかっていません。

    >何か特別なことをやろうとしていますか?
    初めに戻りますが、以下のサイトの
    「10行でズバリ」の手順を基に作ったサービスを利用しており、
    アクセスしているWebサイトも新規に作ったもので特に何もしていません。
    (逆に何もしていないのが原因かもしれません)
    もっと必要な手順(ポート解放やらWebサイト側での認証処理)があるような気がしてネットサーフィンを続けていますが、
    接続できなかったので質問させていただきました。

    ◆ソリューション構成
    Webサービス:
    以下サイトの手順を元に作成
    (サイトの手順通り。ここのバインドはHTTPになっているが、コンソールでTCPに変更しているので問題ない認識)

    ・10 行でズバリ!! サービスの作成 (WCF) (C#)
    http://code.msdn.microsoft.com/10-WCF-C-620ab391

    コンソール:
    以下サイトの手順を元に作成(上で作成したサービスを利用)
    手順では、HTTPになっているのをTCPに変更(その際のconfigが上記)

    10 行でズバリ!! サービスの起動 (WCF のホスティング) (C#)
    http://code.msdn.microsoft.com/10-WCF-C-615b8ee6
    Webサイト:
    新規ソリューションから作ったWebサイトプロジェクトを作成。
    そのWebサイトにWebサービスへアクセスできるように書き換えをした程度で、特に難しいことは何もしていません。
    (configは上記のとおり)

    ◆参考サイト
    ・Windows Communication Foundation (WCF)
    http://msdn.microsoft.com/ja-jp/netframework/aa663324.aspx

    2012年7月20日 4:36
  • こんにちは。

    Windows認証が何かを知る必要があるのではないでしょうか?

    ここが分かりやすいかも:Windows 認証 http://msdn.microsoft.com/ja-jp/library/cc419748.aspx

    その上で、以下を読んでみてください。

    Windows 認証エラーのデバッグ
    http://msdn.microsoft.com/ja-jp/library/bb463274.aspx

    2012年7月21日 4:40
  • こんにちは。


    と、ここまでを踏まえたうえで、

    どのような接続環境であるか?

    例えば、
    ブラウザ(インターネット)--FW--(イントラネット)--IIS(WEB App)--WCF Service(SelfHost) という形なのか
    ブラウザ(イントラネット)--IIS(WEB App)--WCF Service(SelfHost)という形なのか。


    そのうえで、
    ・何から、どの部分を、何を守るのか?
    ・統合Windows認証を行う意味があるのか?適しているのか?
    ・AD(Active Directory)は利用可能なのか?
    ・どの部分を統合Windows認証とするのか?

    など、いくつか考えなければならない事があるはずです。


    簡単に言えば(かなり簡単に言えばですが・・)

    すべてがイントラネット内であり、ブラウザがIEで、ADが運用されているのであれば、ほとんど何も考えずに、統合Windows認証を行うことができます。なぜなら、利用者(ブラウザ)は既にADドメインにログイン(認証済)しているからです。

    IIS--WCF間を暗号化したいだけであれば、統合Windows認証である必要は無いかもしれません。その場合はMessageベースの暗号化のみで良いと思います。この場合は、簡単にメッセージ時内容を傍受されたくない、などの理由になるかと思います。

    匿名認証である場合、IIS-WCF間は統合Windows認証である意味が若干弱くなると思います。なぜなら、IISへは誰でもログインできるからです。これに伴い、サービス事態を誰でも利用できるという事になります。この場合、WCF Serviceへ直接アクセスする対象を制御するという事であれば、通信相手のIP アドレスで制御したりといったことも考えられます。状況に合わせて、IP制限、メッセージの暗号化などを組み合わせたり、証明書での認証を必要とするかもしれません。

     

    結局、何から、どの部分を、何を守るのか?を考える必要があるというのは、こういった事です。

    2012年7月23日 8:09
  • Keiichi Oumi様

    返信が遅くなってしまい、申し訳ございません。
    また、解説ありがとうございました。

    結局、何から、どの部分を、何を守るのか?を考える必要があるというのは、こういった事です。

    特に何を守ろうとかといった考えではないませんでした。
    また、Active Directoryなどの知識も無いので、一度頂いたサイトを基に調べなおしてみようと思います。
    (「運用されているのであればー」とありますが、そもそもどういった内容かも把握していない為)

    調査に時間もかかる上、一旦はセキュリティをnoneで作業を進めようと考えていますので、当質問を完了とさせていただきます。
    (セキュリティの必要性も別途検討)

    我儘な私に参考サイトや情報を提示いただき、ありがとうございました。
    不明点が別途でるかもしれませんが、その際はよろしくお願いいたします。

    2012年7月24日 5:51