Programmatically assigning IIS Application Pool Identity “users” to Groups

我怕爱的太早我们不能终老 提交于 2019-12-05 09:02:39

Thanks for your well-written question. It is exactly the problem that I was trying to solve last night and it gave me enough to go on that I was able finally cobble together an answer that uses only managed code. There were three steps that I found to getting the framework to find and work with the virtual user:

  • using new System.Security.Principal.NTAccount(@"IIS APPPOOL\<appPoolName>") to get a handle on the account.
  • using .Translate(typeof (System.Security.Principal.SecurityIdentifier)) to convert it to a SID
  • understanding that Principal.FindByIdentity() treats that SID like it is a group, rather than a user

A final working program (Windows Server 2012 for my test) is as follows:

using System;
using System.DirectoryServices.AccountManagement;

namespace WebAdminTest
{
    internal class Program
    {
        private static void Main(string[] args)
        {
            var user = new System.Security.Principal.NTAccount(@"IIS APPPOOL\10e6c294-9836-44a9-af54-207385846ebf");
            var sid = user.Translate(typeof (System.Security.Principal.SecurityIdentifier));

            var ctx = new PrincipalContext(ContextType.Machine);

            // This is weird - the user SID resolves to a group prinicpal, but it works that way.
            var appPoolIdentityGroupPrincipal = GroupPrincipal.FindByIdentity(ctx, IdentityType.Sid, sid.Value);

            Console.WriteLine(appPoolIdentityGroupPrincipal.Name);
            Console.WriteLine(appPoolIdentityGroupPrincipal.DisplayName);

            GroupPrincipal targetGroupPrincipal = GroupPrincipal.FindByIdentity(ctx, "Performance Monitor Users");

            // Making appPoolIdentity "group" a member of the "Performance Monitor Users Group"
            targetGroupPrincipal.Members.Add(appPoolIdentityGroupPrincipal);
            targetGroupPrincipal.Save();

            Console.WriteLine("DONE!");
            Console.ReadKey();
        }
    }
}

A solution presented itself sooner than I expected, though it's not the one I preferred. For anyone interested, there are a couple of additional options on this pinvoke page. The managed solution did not work for me, but the sample using DllImport worked. I ended up adjusting the sample to handle arbitrary groups based on mapping an enum to SID strings, and including another DllImport for:

[DllImport("advapi32.dll", SetLastError = true)]
static extern bool ConvertStringSidToSid(
    string StringSid,
    out IntPtr ptrSid);

The modified (working) function looks something like this:

static public bool AddUserToGroup(string user, UserGroup group)
{
    var name = new StringBuilder(512);
    var nameSize = (uint)name.Capacity;
    var refDomainName = new StringBuilder(512);
    var refDomainNameSize = (uint)refDomainName.Capacity;
    var sid = new IntPtr();
    switch (group)
    {
        case UserGroup.PerformanceMonitorUsers:
            ConvertStringSidToSid("S-1-5-32-558", out sid);
            break;
        case UserGroup.Administrators:
            ConvertStringSidToSid("S-1-5-32-544", out sid);
            break;
        // Add additional Group/cases here.
    }

    // Find the user and populate our local variables.
    SID_NAME_USE sidType;
    if (!LookupAccountSid(null, sid, name, ref nameSize,
        refDomainName, ref refDomainNameSize, out sidType))
        return false;

    LOCALGROUP_MEMBERS_INFO_3 info;
    info.Domain = user;

    // Add the user to the group.
    var val = NetLocalGroupAddMembers(null, name.ToString(), 3, ref info, 1);

    // If the user is in the group, success!
    return val.Equals(SUCCESS) || val.Equals(ERROR_MEMBER_IN_ALIAS);
}

Hopefully this will be of interest to someone else, and I would still like to know if anyone comes across a working, fully managed solution.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!