与SAM一起使用System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials时出现奇怪的错误 [英] Strange Error When Using System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials with SAM

查看:88
本文介绍了与SAM一起使用System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials时出现奇怪的错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在通过IIS 6.0托管WCF Web服务。我的应用程序池在本地Administrator帐户下运行,并且为访问Web服务定义了其他本地用户。我编写了以下代码来验证用户:

I am hosting a WCF Web Service with IIS 6.0. My application pool is running under a local Administrator account, and I have other local users defined for accessing the Web Service. I've written the following code to validate users:


//Any public static (Shared in Visual Basic) members of this type are thread safe
public static PrincipalContext vpc;

//static initializer
static UserManagement()
{
    vpc = new PrincipalContext(ContextType.Machine);
}

//Determines whether the given credentials are for a valid Administrator
public static bool validateAdminCredentials(string username, string password)
{
    using (PrincipalContext principalContext = new PrincipalContext(ContextType.Machine))
    {
        if (vpc.ValidateCredentials(username, password))
        {
            using (UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, username))
            {
                foreach (GroupPrincipal gp in user.GetGroups())
                {
                    try
                    {
                        if (gp.Name.Equals("Administrators"))
                        {
                            return true;
                        }
                    }
                    finally
                    {
                        gp.Dispose();
                    }
                }
            }
        }

        return false;
    } //end using PrincipalContext
}

...结束class:

...and in another class:


//verify the user's password
if (!UserManagement.vpc.ValidateCredentials(username, password))
{
    string errorMsg = string.Format("Invalid credentials received for user '{0}'", username);
    throw new Exception(errorMsg);
}

(注意:我仅将公共静态PrincipalContext(vpc)用于调用ValidateCredentials方法;我创建了一个不同的临时PrincipalContext用于创建,删除和查找用户和组,因为在尝试对所有内容使用全局PrincipalContext时遇到各种与COM相关的错误。

(Note: I am using the public static PrincipalContext (vpc) solely for calling the ValidateCredentials method; I create a different, temporary PrincipalContext for creating, deleting, and finding users and groups, as I got various COM-related errors when I tried using the global PrincipalContext for everything).

因此,在大多数情况下,这段代码可以正常工作。但是,间歇性地,出现以下错误:

So, most of the time, this code works wonderfully. However, intermittently, I get the following error:

不允许同一用户使用多个用户名与服务器或共享资源进行多次连接。断开与服务器或共享资源的所有先前连接,然后重试。 (来自HRESULT的异常:0x800704C3)

Multiple connections to a server or shared resource by the same user, using more than one user name, are not allowed. Disconnect all previous connections to the server or shared resource and try again. (Exception from HRESULT: 0x800704C3)

应用程序:
System.DirectoryServices.AccountManagement

Application: System.DirectoryServices.AccountManagement

堆栈跟踪:位于System.DirectoryServices.AccountManagement.CredentialValidator.BindSam(字符串目标,字符串userName,字符串密码)处的
,位于System.DirectoryServices.AccountManagement.CredentialValidator.Validate(字符串userName,字符串密码)处的
在System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName,String password)
在MyNamespace.User..ctor(String username,String password)

Stack Trace: at System.DirectoryServices.AccountManagement.CredentialValidator.BindSam(String target, String userName, String password) at System.DirectoryServices.AccountManagement.CredentialValidator.Validate(String userName, String password) at System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials(String userName, String password) at MyNamespace.User..ctor(String username, String password)

一旦发生错误,我将继续获取它,直到重新启动整个服务器(不仅是IIS)。我尝试过重新启动应用程序池和/或IIS,但是直到重新启动计算机后该错误才会消失。我也曾尝试对ValidateCredentials的每次调用(通过我使用的实例)实例化一个新的PrincipalContext(我不必这样做),但最终仍然会遇到相同的错误。根据我在System.DirectoryServices.AccountManagement(msdn文档,文章)上阅读的内容,我相信我使用的是正确的,但是此错误使我的应用程序瘫痪!我需要(并且应该能够)从来自多个客户端的Web服务请求中验证本地用户凭据。难道我做错了什么?对于解决此问题的任何帮助将不胜感激...

Once the error occurs, I continue to get it until I restart my entire server (not just IIS). I've tried restarting my application pool and/or IIS, but the error does not go away until I restart the machine. I've also tried instantiating (via a using block) a new PrincipalContext for every call to ValidateCredentials (which I shouldn't have to do), but I still eventually get the same error. From what I've read on System.DirectoryServices.AccountManagement (msdn docs, articles), I believe I'm using it correctly, but this error is crippling my application! I need (and should be able) to validate local user credentials from web service requests coming from multiple clients. Am I doing something wrong? Any help on solving this issue would be much appreciated...

推荐答案


  1. 这种类型的任何公共静态(在Visual Basic中为Shared)成员都是线程安全的
    此样板文字使很多人感到困惑。这意味着该类型暴露的所有静态成员都是线程安全的。这并不意味着存储在静态成员中的任何类型实例都将是线程安全的。

  1. "Any public static (Shared in Visual Basic) members of this type are thread safe" This boilerplate text confuses a lot of people. It means that any static members exposed by the type are thread-safe. It doesn't mean that any instance of the type stored in a static member will be thread-safe.

您的 validateAdminCredentials 方法创建一个新的 PrincipalContext 对象,但随后继续使用静态 vpc 实例来验证凭据。由于您对静态实例的访问没有锁,并且实例方法也不是线程安全的,因此最终您将获得两个线程尝试同时访问同一实例,这将无法正常工作。

Your validateAdminCredentials method creates a new PrincipalContext object, but then proceeds to use the static vpc instance to validate the credentials. Since you have no locks around the access to the static instance, and the instance methods are not thread-safe, you'll eventually get two threads trying to access the same instance at the same time, which will not work.

尝试删除 vpc 字段,并使用 principalContext 实例来验证证书。您需要在每次调用时创建和处理 PrincipalContext

Try removing the vpc field and using the principalContext instance to validate the credentials. You'll need to create and dispose of the PrincipalContext on every call.

此外,您可以使用以下方法代替手动迭代用户的组 IsMemberOf 方法来测试组中的成员身份。

Also, rather than manually iterating the user's groups, you can use the IsMemberOf method to test for membership in a group.

public static bool ValidateCredentials(string username, string password)
{
    using (PrincipalContext principalContext = new PrincipalContext(ContextType.Machine))
    {
        return principalContext.ValidateCredentials(username, password);
    }
}

public static bool validateAdminCredentials(string username, string password)
{
    using (PrincipalContext principalContext = new PrincipalContext(ContextType.Machine))
    {
        if (principalContext.ValidateCredentials(username, password))
        {
            using (UserPrincipal user = UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, username))
            using (GroupPrincipal group = GroupPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, "Administrators"))
            {
                if (null != group && user.IsMemberOf(group))
                {
                    return true;
                }
            }
        }

        return false;
    }
}

这篇关于与SAM一起使用System.DirectoryServices.AccountManagement.PrincipalContext.ValidateCredentials时出现奇怪的错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆