質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.35%

WindowsフォームアプリからサーバへのWindows認証実装方法について

受付中

回答 1

投稿 編集

  • 評価
  • クリップ 3
  • VIEW 2,433

yukidaruma.

score 7

 前提・実現したいこと

WindowsフォームアプリからWindows Server(Webサービス)への認証にWindows認証を使用しようと考えており、その実装方法とローカルPCでの検証方法についてご教示いただきたいです。
ローカルPCでの検証については検証用のサーバが準備できていないため事前に検証をしたく思っているのですが、Active Directoryが無いためできないのかなと考えています。
不足情報等ございましたらご指摘ください。宜しくお願いします。

 試したこと

Webサービスを呼び出す - asmx SOAP Webサービスの呼び出し (C#プログラミング)

上記サイトを参考にローカル環境でWebサービスおよびWindowsフォームアプリを作成してみましたが、例の通りだと匿名アクセスのため上手くいきますが、IISの設定をWindows認証に設定するとエラーが発生してしまいました。

[IISの設定変更箇所]
Default Web Site内に作成した当該アプリケーションに対し[機能ビュー]から[認証]を開き、「Windows認証」のみ有効化し、その他は無効化しました。

▼エラー内容

System.ServiceModel.Security.MessageSecurityException: 'この HTTP 要求は、クライアントの認証方式 'Anonymous' では承認されません。サーバーから受信した認証ヘッダーは 'Negotiate,NTLM' でした。'
内部例外
WebException: リモート サーバーがエラーを返しました: (401) 許可されていません


▼Webサービス(自動生成されたコメント部を省いています)

[WebService(Namespace = "http://localhost")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
[System.ComponentModel.ToolboxItem(false)]
public class SimpleWebService : System.Web.Services.WebService {
    [WebMethod]
    public string HelloWorld() {
        return "Hello World";
    }
}


▼Windowsフォームアプリ

private void button1_Click(object sender, EventArgs e) {
    SimpleWebServiceReference.SimpleWebServiceSoapClient cl = new SimpleWebServiceReference.SimpleWebServiceSoapClient();
    string value = cl.HelloWorld();  // ここでエラー発生
    textBox1.Text = value;
}


ブラウザからWebサービスにアクセスした場合は以下の通り表示されます。
イメージ説明

IISの設定は以下の通りです。
イメージ説明

 補足情報(FW/ツールのバージョンなど)

Windowsフォームアプリ → Webサービス → SQL Serverという構成を想定しており、Webサービス、SQL Server、Active Directoryは同サーバ内に構築予定です。

■クライアントOS:Windows7
■サーバ:Windows Server(バージョン未定)
■DB:SQL Server 2017
■開発ツール:Visual Studio Professional 2017
■言語:C#

 [追記]回答に対して試したこと

クレデンシャルを送る処理を追加しましたが同様の箇所でエラーが発生してしまいました。エラーメッセージは"Anonymous"の部分が"Negotiate"に変わりました。

▼Windowsフォームアプリ

        private void button1_Click(object sender, EventArgs e) {
            System.ServiceModel.BasicHttpBinding MyHttpBinding = new System.ServiceModel.BasicHttpBinding(System.ServiceModel.BasicHttpSecurityMode.TransportCredentialOnly);
            MyHttpBinding.Security.Transport.ClientCredentialType = System.ServiceModel.HttpClientCredentialType.Windows;
            System.ServiceModel.EndpointAddress MyAuthASMXWebServiceAddress = new System.ServiceModel.EndpointAddress(new Uri("http://localhost/SimpleAsmxWebService/SimpleWebService.asmx"));
            SimpleWebServiceReference.SimpleWebServiceSoapClient cl = new SimpleWebServiceReference.SimpleWebServiceSoapClient(MyHttpBinding, MyAuthASMXWebServiceAddress);
            cl.ClientCredentials.Windows.ClientCredential.Domain = "localhost";
            cl.ClientCredentials.Windows.ClientCredential.UserName = "username";
            cl.ClientCredentials.Windows.ClientCredential.Password = "password";

            string value = cl.HelloWorld();    // ここでエラー発生
            textBox1.Text = value;
        }


▼エラー内容

System.ServiceModel.Security.MessageSecurityException: 'この HTTP 要求は、クライアントの認証方式 'Negotiate' では承認されません。サーバーから受信した認証ヘッダーは 'Negotiate,NTLM' でした。'
内部例外
WebException: リモート サーバーがエラーを返しました: (401) 許可されていません
  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • SurferOnWww

    2018/10/19 10:37

    > 現状困っているのはローカル環境に閉じた話なのでADは関係ない認識で合っています。 ← であれば Active Directory, Windows Server のタグは外していただくようお願いします。SQL Server も関係ないので外してください。また、ASP.NET のタグを付けてください。

    キャンセル

  • SurferOnWww

    2018/10/19 10:43

    最終的な運用環境での話、例えば「Active Driectory ドメイン環境でドメインに属する Windows 認証を要求する Web サーバーの Web サービスに、ドメインユーザーが Windows Forms アプリでアクセスして、シングルサインオンは有効か?」という質問があれば、新たに別のスレッドで質問されることをお勧めします。

    キャンセル

  • yukidaruma.

    2018/10/20 08:58

    タグの件、ご指摘ありがとうございます。対応いたしました。また、運用環境での件についても確かに切り分けて質問させていただいた方が良さそうですね。不慣れなもので恐縮です。

    キャンセル

回答 1

+2

ブラウザからWebサービスにアクセスした場合は以下の通り表示されます。

ユーザー情報を入力するダイアログが表示されませんか? ダイアログが出ないとすると何か変なのですが(匿名認証が有効になっているとか?)、とりあえずそれはちょっと置いといて・・・

アップされた「Windowsフォームアプリ」を見るとクレデンシャルが送られてないですよね。

以下の記事の「Windows ストア アプリケーションから Windows 認証を用いて ASMX Web Service を取り込む」のセクションのように、クレデンシャルを送らないとダメだと思います。

助けて下さい! ASMX Web サービスに接続するにはどうしたらいいのですか?
https://blogs.msdn.microsoft.com/japan_platform_sdkwindows_sdk_support_team_blog/2013/12/09/asmx-web-123/

分からないことがあれば聞いてください。

【追記】

下の 2018/10/20 10:15 の私のコメントで「後で自分がどのようにしたかもう少し詳しい情報を書きます」と書きましたが、それを以下に追記します。

まず開発環境ですが以下の通りです。

Web サービス
・Windows 10 Pro 64-bit
・Visual Studio Pro 2010
・ASP.NET Web サイト(注:テンプレートは「空」ではない)
・.NET 4
・ローカル IIS10 (Default Web Site 下のアプリケーションとして設定)
・SSL 使用せず
・IE11

Windows Forms アプリ
・Windows 10 Pro 64-bit
・Visual Studio Community 2015
・.NET 4.6.1

質問者さんが参考にされている記事とほぼ同じ手順で HelloWorld のみの Web サービスを追加し、質問者さんが行ったように IIS Manager で Windows 認証を有効にし匿名認証ほか他はすべて無効に設定します。

IE11 を立ち上げて、アドレスバーに上記で追加した Web サービスの URL を張り付けて要求をかけると、以下の認証情報を要求するダイアログが表示されます。(Windows 認証は IE と IIS で実現されている機能です。必ず IE を使ってください)

イメージ説明

PC を立ち上げる時ログインに使っている自分のアカウント名とパスワードを入力して[OK]ボタンをクリックすれば、質問者さんが筆問にアップされた画像と同じものが表示されます。

イメージ説明

HelloWorld をクリックしていって期待通りの応答が返ってくることを確認後、上の画像の認証ダイアログで使ったのと同じコンピュータ名、アカウント名、パスワードをそれぞれ以下のように Domain、UserName、Password に設定します。

private void button1_Click(object sender, EventArgs e)
{
    System.ServiceModel.BasicHttpBinding binding =
        new System.ServiceModel.BasicHttpBinding(
              System.ServiceModel.BasicHttpSecurityMode.TransportCredentialOnly);
    binding.Security.Transport.ClientCredentialType =
        System.ServiceModel.HttpClientCredentialType.Windows;
    System.ServiceModel.EndpointAddress address =
        new System.ServiceModel.EndpointAddress(
             new Uri("http://localhost/WindowsAuthntication/WebService.asmx"));

    ServiceReference1.WebServiceSoapClient proxy =
        new ServiceReference1.WebServiceSoapClient(binding, address);

    proxy.ClientCredentials.Windows.ClientCredential.Domain = "MyComputer";
    proxy.ClientCredentials.Windows.ClientCredential.UserName = "surfe";
    proxy.ClientCredentials.Windows.ClientCredential.Password = "*****************";

    string value = proxy.HelloWorld();
    label1.Text = value;
}


以上で Windows Forms アプリからも認証は通るようになり、Web サービスから期待した応答が返ってきます。

ちなみに、Domain, UserName, Password の設定なしの場合、現在のユーザーのクレデンシャルが自動的に使われるようで(想像です)、認証が通るという結果になりました。ご参考まで。

質問者さんのケースでは、IE でアクセスした場合の認証ダイアログが出ないとのことですが、そのあたりの理由は分かりません。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/10/23 23:00

    > 実際は会社管理のADのドメインには参加している状態 ← 今回の話は最初から質問者さんの組織のシステム管理者に聞くべきことだったのでは? グループポリシーとか ADFS とか第三者が知る由もない何かがあるのかも。質問者さんご自身も知らないようですのでここで何も知らない第三者とは話はできないように思います。

    キャンセル

  • 2018/10/24 22:19

    開発マシンはドメインに参加しているということですかね?
    .Netの内部実装がどうなってるか不明ですが、
    ドメイン環境ならClientCredential.Domainにlocalhostではなくきちんとドメインを指定するか、
    指定するのをやめてClientCredential.UserName = "Domain\\username"
    としてみたらいいんじゃないですか?
    ドメインに所属していないのであれば、ClientCredential.Domainにlocalhostではなくちゃんとしたコンピューター名を指定してみてください。

    キャンセル

  • 2018/11/03 14:31

    返信遅くなり申し訳ありません。本件についてあまり時間が取れない状況となってしまい、検証できていない状況です。進展ありましたら追記させていただきます。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.35%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る