2

我正在尝试将我的第一个 CLR 例程添加到 SQLServer 2008(将很快升级到 2014)。目标是向 Active Directory 添加一个用户对象,传入十几个属性值,以根据来自 ERP 接口的数据创建用户(接口工作正常,数据良好)。一位同事创建了一个包装 PrincipalContext 的紧凑 C# 类,实际上从另一个工作应用程序中获取了代码并对其进行了一些简化(见下文)。

我们能够打开 CLR,将 DB 设置为 TRUSTWORTHLY,等等,然后使用 UNSAFE 选项为他的代码及其所需资源执行 CREATE ASSEMBLY,因为该代码不是 Microsoft 审查的 .NET 类子集的一部分在 SQLServer 中运行:

alter database Util SET TRUSTWORTHY ON

CREATE/ALTER ASSEMBLY SystemDSProtocols
FROM 'C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.DirectoryServices.Protocols.dll'
WITH PERMISSION_SET = UNSAFE

CREATE/ALTER ASSEMBLY SystemDSAccountManagement
FROM 'C:\Program Files\Reference Assemblies\Microsoft\Framework\v3.5\System.DirectoryServices.AccountManagement.dll'
WITH PERMISSION_SET = UNSAFE

CREATE/ALTER ASSEMBLY XXXXXXXXX_CLR
FROM 'C:\XXXXXXX\XXXXX\XXXXXXXX.CLR\XXXXXXXX.CLR.dll'
WITH PERMISSION_SET = UNSAFE

(所有创建和后续的 ALTER 都运行良好,每当我们更改我在这里模糊的自定义类库 XXXXXXX_CLR 时,我们都会更改最后一个...... CLR 存储过程创建良好,并执行 OK,直到它尝试保存用户通过 PrincipalContext 对象。我们得到以下代码和错误消息。

我已经阅读了 50 个网页来寻找这个错误的答案;我们暂时让 SQLserver 以域管理员身份运行的用户(开发系统——我敢肯定这是糟糕的做法),从具有域管理员权限的登录 SQL 用户调用它,给定代码能够使用的域服务帐户传入显式 .NET AD 连接域管理员,将用户和密码选项从对 PrincipalContext 的调用中移除,以查看 SQLServer 的用户或调用用户的 privs 是否会控制它,在 PrincipalContext 构造函数调用中尝试不同的选项组合等.

        // Create PrincipalContext
        PrincipalContext principalContext = null;
        try
        {
            // as given, used Simplebind only
            principalContext = new PrincipalContext(
                ContextType.Domain,    
                LdapName,              // Domain name  xxxx.yyyy
                StudentContainer,      // ou=aaaa,ou=bbbb,dc=xxxx,dc=yyyy
                ContextOptions.Negotiate
                //ContextOptions.SecureSocketLayer
                //ContextOptions.SimpleBind,
                //              | ContextOptions.Signing
                                | ContextOptions.Sealing,
                //              | ContextOptions.ServerBind
                ContextUser,
                ContextPassword
            );
        }
        catch (Exception ex)
        {
            throw new Exception("Failed to create PrincipalContext. Exception:", ex);
        }

        using (principalContext)
        {
            using (var p = new MaricopaUserPrincipal(principalContext))
            {
                p.SamAccountName = xxxxUserId;
                p.Name = xxxxUserName;

.... 等剩余属性....我们已经使用 FIM 和其他 C# 中间件库调用多年,忽略细节...我们肯定有正确的 AD 属性覆盖在我们传入的参数中但我不想在这里暴露所有这些。

所以这是总是出现的错误消息(我知道它正在执行 C# CLR 代码,因为我在类库 CLR 中有其他属性验证问题要处理,它最终到了调用 PrincipalContext 并失败的地步那里):

Msg 6522, Level 16, State 1, Procedure sp_XXXXXAddXXXXX_CLR, Line 0
A .NET Framework error occurred during execution of user-defined routine or aggregate "sp_XXXXXAddXXXXX_CLR": 
System.Exception: Could not save user principal. Exception: ---> System.UnauthorizedAccessException: General access denied error
System.UnauthorizedAccessException: 
   at System.DirectoryServices.AccountManagement.ADStoreCtx.Insert(Principal p)
   at System.DirectoryServices.AccountManagement.Principal.Save()
   at XXXXXXX.CLR.xxxxxManager.CreateUser(String xxxxUserId, String xxxxUserName, ...other params follow)
System.Exception: at XXXXXXX.CLR.xxxxxManager.CreateUser(String xxxxUserId, String xxxxUserName, ...other params follow)

我阅读了一些有关 Windows 身份“模拟”的内容,但我不明白为什么在所有涉及的服务都作为域管理员权限运行时,我什至无法让 AD 运行 PrincipalContext 调用。我知道我不能真正使用这种方法(安全非入门者),但想知道为什么它不起作用以及在这里尝试什么替代方法,这样我就可以找到一个可以用于生产实施的解决方案。在将运行它的服务帐户放入域管理员组 BTW 后,我确实退回了 SQLServer。

非常感谢您对这个冗长的问题的友好审查。

4

0 回答 0