セキュリティ メカニズムとして Windows 認証を使用する場合、セキュリティ サポート プロバイダー インターフェイス (SSPI) はセキュリティ プロセスを処理します。 SSPI レイヤーでセキュリティ エラーが発生すると、Windows Communication Foundation (WCF) によって表示されます。 このトピックでは、エラーの診断に役立つフレームワークと一連の質問について説明します。
Kerberos プロトコルの概要については、 Kerberos の説明を参照してください。SSPI の概要については、 SSPI を参照してください。
Windows 認証の場合、WCF は通常、クライアントとサービスの間で Kerberos 相互認証を実行する ネゴシエート セキュリティ サポート プロバイダー (SSP) を使用します。 Kerberos プロトコルを使用できない場合、既定では WCF は NT LAN Manager (NTLM) にフォールバックします。 ただし、Kerberos プロトコルのみを使用するように WCF を構成できます (Kerberos が使用できない場合は例外をスローします)。 制限付き形式の Kerberos プロトコルを使用するように WCF を構成することもできます。
デバッグ方法
基本的な方法は次のとおりです。
Windows 認証を使用しているかどうかを確認します。 他のスキームを使用している場合、このトピックは適用されません。
Windows 認証を使用している場合は、WCF 構成で Kerberos ダイレクトとネゴシエートのどちらを使用するかを決定します。
構成で Kerberos プロトコルと NTLM のどちらを使用しているかを判断したら、正しいコンテキストでエラー メッセージを理解できます。
Kerberos プロトコルと NTLM の可用性
Kerberos SSP では、ドメイン コントローラーが Kerberos キー配布センター (KDC) として機能する必要があります。 Kerberos プロトコルは、クライアントとサービスの両方がドメイン ID を使用している場合にのみ使用できます。 他のアカウントの組み合わせでは、次の表に示すように NTLM が使用されます。
テーブル ヘッダーには、サーバーで使用されるアカウントの種類が表示されます。 左側の列には、クライアントで使用されるアカウントの種類が表示されます。
ローカル ユーザー | ローカル システム | ドメイン ユーザー | ドメイン マシン | |
---|---|---|---|---|
ローカル ユーザー | NTLM | NTLM | NTLM | NTLM |
ローカル システム | 匿名 NTLM | 匿名 NTLM | 匿名 NTLM | 匿名 NTLM |
ドメイン ユーザー | NTLM | NTLM | Kerberos | Kerberos |
ドメイン マシン | NTLM | NTLM | Kerberos | Kerberos |
具体的には、次の 4 つのアカウントの種類があります。
ローカル ユーザー: コンピューターのみのユーザー プロファイル。 たとえば、
MachineName\Administrator
やMachineName\ProfileName
などです。ローカル システム: ドメインに参加していないコンピューター上の組み込みアカウント SYSTEM。
ドメイン ユーザー: Windows ドメインのユーザー アカウント。 たとえば、
DomainName\ProfileName
と指定します。ドメイン マシン: Windows ドメインに参加しているマシンで実行されているマシン ID を持つプロセス。 たとえば、
MachineName\Network Service
と指定します。
注
サービス資格情報は、ServiceHost クラスのOpen メソッドが呼び出されたときにキャプチャされます。 クライアント資格情報は、クライアントがメッセージを送信するたびに読み取られます。
Windows 認証に関する一般的な問題
このセクションでは、一般的な Windows 認証の問題と考えられる解決策について説明します。
Kerberos プロトコル
Kerberos プロトコルに関する SPN/UPN の問題
Windows 認証を使用していて、Kerberos プロトコルが SSPI によって使用またはネゴシエートされる場合、クライアント エンドポイントが使用する URL には、サービスのホストの完全修飾ドメイン名をサービス URL 内に含める必要があります。 これは、サービスが実行されているアカウントが、コンピューターが Active Directory ドメインに追加されたときに作成されるマシン (既定) サービス プリンシパル名 (SPN) キーにアクセスできるものとします。これは、ネットワーク サービス アカウントでサービスを実行することによって最も一般的に行われます。 サービスがマシンの SPN キーにアクセスできない場合は、クライアントのエンドポイント ID でサービスが実行されているアカウントの正しい SPN またはユーザー プリンシパル名 (UPN) を指定する必要があります。 WCF と SPN と UPN の連携の詳細については、「 サービス ID と認証」を参照してください。
Web ファームや Web ガーデンなどの負荷分散シナリオでは、一般的な方法として、アプリケーションごとに一意のアカウントを定義し、そのアカウントに SPN を割り当て、そのアカウントですべてのアプリケーションのサービスが確実に実行されるようにします。
サービスのアカウントの SPN を取得するには、Active Directory ドメイン管理者である必要があります。 詳細については、「 Windows 用 Kerberos テクニカル サプリメント」を参照してください。
Kerberos プロトコル ダイレクトでは、ドメイン コンピューター アカウントでサービスを実行する必要があります
これは、次のコードに示すように、 ClientCredentialType
プロパティが Windows
に設定され、 NegotiateServiceCredential プロパティが false
に設定されている場合に発生します。
WSHttpBinding b = new WSHttpBinding();
// By default, the WSHttpBinding uses Windows authentication
// and Message mode.
b.Security.Message.NegotiateServiceCredential = false;
Dim b As New WSHttpBinding()
' By default, the WSHttpBinding uses Windows authentication
' and Message mode.
b.Security.Message.NegotiateServiceCredential = False
対処するには、ドメインに参加しているコンピューターで、ネットワーク サービスなどのドメイン マシン アカウントを使用してサービスを実行します。
委任には資格情報ネゴシエーションが必要
委任で Kerberos 認証プロトコルを使用するには、資格情報ネゴシエーション ("マルチレッグ" または "マルチステップ" Kerberos とも呼ばれます) を使用して Kerberos プロトコルを実装する必要があります。 資格情報ネゴシエーションなしで Kerberos 認証 ("ワンショット" または "シングルレッグ" Kerberos と呼ばれることもあります) を実装すると、例外がスローされます。
資格情報ネゴシエーションを使用して Kerberos を実装するには、次の手順を実行します。
AllowedImpersonationLevelを Delegation に設定して委任を実装します。
SSPI ネゴシエーションが必要:
標準バインドを使用している場合は、
NegotiateServiceCredential
プロパティをtrue
に設定します。カスタム バインドを使用している場合は、
Security
要素のAuthenticationMode
属性をSspiNegotiated
に設定します。
NTLM の使用を禁止して Kerberos を使用するには、SSPI ネゴシエーションを要求します。
次のステートメントを使用して、コードでこれを行います。
ChannelFactory.Credentials.Windows.AllowNtlm = false
または、
allowNtlm
属性をfalse
に設定することで、構成ファイルでこれを行うことができます。 この属性は、<windows>に含まれています。
NTLM プロトコル
ネゴシエート SSP は NTLM にフォールバックしますが、NTLM は無効です
AllowNtlm プロパティは false
に設定されているため、NTLM が使用されている場合は、Windows Communication Foundation (WCF) によって例外がスローされます。 このプロパティを false
に設定しても、NTLM 資格情報がネットワーク経由で送信されない場合があります。
NTLM へのフォールバックを無効にする方法を次に示します。
CalculatorClient cc = new
CalculatorClient("WSHttpBinding_ICalculator");
cc.ClientCredentials.Windows.AllowNtlm = false;
Dim cc As New CalculatorClient("WSHttpBinding_ICalculator")
cc.ClientCredentials.Windows.AllowNtlm = False
NTLM ログオンが失敗する
クライアント資格情報がサービスで無効です。 ユーザー名とパスワードが正しく設定され、サービスが実行されているコンピューターに認識されているアカウントに対応していることを確認します。 NTLM では、指定された資格情報を使用してサービスのコンピューターにログオンします。 資格情報は、クライアントが実行されているコンピューターで有効な場合もありますが、サービスのコンピューターで資格情報が有効でない場合、このログオンは失敗します。
匿名 NTLM ログオンが発生したが、匿名ログオンは既定で無効になっている
クライアントを作成する場合、次の例に示すように、 AllowedImpersonationLevel プロパティは Anonymous に設定されますが、既定では、サーバーは匿名ログオンを許可しません。 これは、WindowsServiceCredential クラスの AllowAnonymousLogons プロパティの既定値がfalse
されているために発生します。
次のクライアント コードは、匿名ログオンを有効にしようとします (既定のプロパティが Identification
されていることに注意してください)。
CalculatorClient cc =
new CalculatorClient("WSHttpBinding_ICalculator");
cc.ClientCredentials.Windows.AllowedImpersonationLevel =
System.Security.Principal.TokenImpersonationLevel.Anonymous;
Dim cc As New CalculatorClient("WSHttpBinding_ICalculator")
cc.ClientCredentials.Windows.AllowedImpersonationLevel = _
System.Security.Principal.TokenImpersonationLevel.Anonymous
次のサービス コードは、サーバーによる匿名ログオンを有効にするように既定値を変更します。
Uri httpUri = new Uri("http://localhost:8000/");
ServiceHost sh = new ServiceHost(typeof(Calculator), httpUri);
sh.Credentials.WindowsAuthentication.AllowAnonymousLogons = true;
Dim httpUri As New Uri("http://localhost:8000/")
Dim sh As New ServiceHost(GetType(Calculator), httpUri)
sh.Credentials.WindowsAuthentication.AllowAnonymousLogons = True
偽装の詳細については、「 委任と偽装」を参照してください。
または、組み込みのアカウント SYSTEM を使用して、クライアントが Windows サービスとして実行されています。
その他の問題
クライアント資格情報が正しく設定されていない
Windows 認証では、UserNamePasswordClientCredentialではなく、ClientBase<TChannel> クラスのClientCredentials プロパティによって返されるWindowsClientCredential インスタンスが使用されます。 正しくない例を次に示します。
CalculatorClient cc = new
CalculatorClient("WSHttpBinding_ICalculator");
cc.ClientCredentials.UserName.UserName = GetUserName(); // wrong!
cc.ClientCredentials.UserName.Password = GetPassword(); // wrong!
Dim cc As New CalculatorClient("WSHttpBinding_ICalculator")
cc.ClientCredentials.UserName.UserName = GetUserName() ' wrong!
cc.ClientCredentials.UserName.Password = GetPassword() ' wrong!
正しい例を次に示します。
CalculatorClient cc = new
CalculatorClient("WSHttpBinding_ICalculator");
// This code returns the WindowsClientCredential type.
cc.ClientCredentials.Windows.ClientCredential.UserName = GetUserName();
cc.ClientCredentials.Windows.ClientCredential.Password = GetPassword();
Dim cc As New CalculatorClient("WSHttpBinding_ICalculator")
' This code returns the WindowsClientCredential type.
cc.ClientCredentials.Windows.ClientCredential.UserName = GetUserName()
cc.ClientCredentials.Windows.ClientCredential.Password = GetPassword()
SSPI は使用できません
次のオペレーティング システムは、Windows XP Home Edition、Windows XP Media Center Edition、および Windows Vista Home エディションのサーバーとして使用する場合、Windows 認証をサポートしていません。
さまざまな ID を使用した開発とデプロイ
あるコンピューターでアプリケーションを開発し、別のコンピューターにデプロイし、異なるアカウントの種類を使用して各マシンで認証を行うと、動作が異なる場合があります。 たとえば、 SSPI Negotiated
認証モードを使用して Windows XP Pro コンピューターでアプリケーションを開発するとします。 認証にローカル ユーザー アカウントを使用する場合は、NTLM プロトコルが使用されます。 アプリケーションが開発されたら、ドメイン アカウントで実行される Windows Server 2003 コンピューターにサービスを展開します。 この時点で、クライアントは Kerberos とドメイン コントローラーを使用するため、サービスを認証できません。