11

Loginローカルマシンのクレデンシャルに対してユーザー名とパスワードを検証するメソッドを含むWCFサービスがありますが、一見ランダムな期間が経過すると、一部のユーザーでは機能しなくなります。

実際のログインコマンドは次のようになります。

public UserModel Login(string username, string password, string ipAddress)
{
    // Verify valid parameters
    if (username == null || password == null)
        return null;

    try
    {
        using (var pContext = new PrincipalContext(ContextType.Machine))
        {
            // Authenticate against local machine
            if (pContext.ValidateCredentials(username, password))
            {
                // Authenticate user against database
                using (var context = new MyEntities(Connections.GetConnectionString()))
                {
                    var user = (from u in context.Users
                                where u.LoginName.ToUpper() == username.ToUpper()
                                      && u.IsActive == true
                                      && (string.IsNullOrEmpty(u.AllowedIpAddresses)
                                        || u.AllowedIpAddresses.Contains(ipAddress))
                                select u).FirstOrDefault();

                    // If user failed to authenticate against database
                    if (user == null)
                        return null;

                    // Map entity object to return object and assign session token
                    var userModel = Mapper.Map<User, UserModel>(user);
                    userModel.Token = Guid.NewGuid();
                    userModel.LastActivity = DateTime.Now;

                    // Authenticated users are added to a list on the server
                    // and their login expires after 20 minutes of inactivity
                    authenticatedUsers.Add(userModel);
                    sessionTimer.Start();

                    // User successfully authenticated, so return UserModel to client
                    return userModel;
                }
            }
        }
    }
    catch(Exception ex)
    {
        // This is getting hit
        MessageLog.WriteMessage(string.Format("Exception occurred while validating user: {0}\n{1}", ex.Message, ex.StackTrace));
        return null;
    }

    // If authentication against local machine failed, return null
    return null;
}

これは数日間は正常に機能しているように見えますが、その後、一部のユーザーでは突然機能を停止し、次の例外をスローします。

複数のユーザー名を使用した、同じユーザーによるサーバーまたは共有リソースへの複数の接続は許可されていません。サーバーまたは共有リソースへの以前の接続をすべて切断して、再試行してください。(HRESULTからの例外:0x800704C3)

System.DirectoryServices.AccountManagement.CredentialValidator.BindSam(String target、String userName、String password)で

System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName、String password)で

System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName、String password)で

MyNamespace.LoginService.Login(String username、String password、String ipAddress)のC:\ Users \ me \ Desktop \ somefolder \ LoginService.svc.cs:line 67

67行目は次のとおりです。if (pContext.ValidateCredentials(username, password))

重要かどうかはわかりませんが、エラーメッセージの最後の行は、本番サーバー上のファイルへのパスではなく、開発マシン上のVSソリューションのパスです。

失敗した場合、一部のユーザーのみが失敗しますが、他のユーザーは引き続き正常にログインできます。エラーを一時的に修正するために私が見つけた唯一のことは、実行中iisresetです。Webサイトの停止/開始、またはアプリプールのリサイクルは機能しません。

要求に応じてエラーを再現することはできません。複数のセッションとIPアドレスから同じユーザーでログインしたり、同じブラウザセッションから同時に別のユーザーでログインしたり、ログインボタンをスパムして複数回実行しようとしたりしましたが、すべてが表示されますうまく動作します。

ロギングから、ユーザーが過去に正常にログインできたことがわかります。

2013年3月21日
o 9:03aログインしました
o 1:54pUserBがログインしました
o 1:55pUserAがログインしました
o 2:38pUserBがログインしました
o 3:48pUserBがログインしました
o 5:18pUserAがログインしました
o 6:11pUserBがログインしました

2013年3月22日
o 12:42pUserAがログインしました
o 5:22pUserBがログインしました
o 8:04pUserBがログインしました

2013年3月25日(本日)
o 8:47aログインしました
o 12:38p UserBはログインを試み、失敗します。次の45分間に約15回繰り返した
o 1:58p正常にログインしました
o 2:08p UserBのログイン情報でログインしようとすると、同じエラーで失敗します

ローカルマシンに対して認証する理由は、ユーザーがFTPアクセス用にローカルで作成されたアカウントを持っており、独自のカスタムログインシステムを構築したり、ユーザーに2セットの資格情報を記憶させたりしたくないためです。

コードはユーザーの資格情報のみを認証する必要があり、ユーザーの資格情報に対して他のことは何もしません。を使用する他のコードはなくSystem.DirectoryServices、ファイルIOは実行されておらず、Webアプリケーションの実行に必要なファイル以外のファイルシステム上でローカルにアクセスすることはできません。

数日後に、そのエラーが一見ランダムに表示される原因は何ですか?そして、どうすればそれを修正できますか?

サーバーは、IIS6.0を実行するWindowsServer 2003であり、.NetFramework4.0を使用するようにセットアップされています。

4

1 に答える 1

5

この問題を説明するためにオンラインで見つけることができる最も近いものは、このフォーラムの投稿です。ここでは、ユーザーが同じエラーを経験し、次のようなリプレイを受け取りました。

WinNTプロバイダーは、サーバー環境ではうまく機能しません。私は実際にあなたがはるかに小さな負荷でこれを見ないことに驚いています。私はたった2、3人のユーザーでこれを手に入れることができました。

そしてこのSOコメント

誰かを正しく認証する最良の方法は、@stephbu書き込みとしてLogonUserAPIを使用することです。この投稿で説明されている他のすべての方法は100%機能しません

ここで、「他のすべての方法」には、PrincipalContext.ValidateCredentials

そのように聞こえるのPrincipalContext.ValidateCredentialsは、Windows Server 2003およびIIS6.0で完全に100%信頼できるわけではないため、代わりにLogonUserWinAPIメソッドを使用するように認証コードを書き直しました。

[DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
    string lpszUsername,
    string lpszDomain,
    string lpszPassword,
    int dwLogonType,
    int dwLogonProvider,
    out IntPtr phToken
    );

IntPtr hToken;
if (LogonUser(username, "", password, 
    LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, out hToken))
{
    ...
}
于 2013-03-26T18:13:04.757 に答える