Vanara/UnitTests/PInvoke/NTDSApi/NTDSApiTests.cs

188 lines
7.7 KiB
C#

using NUnit.Framework;
using System.DirectoryServices;
using System.Linq;
using static Vanara.PInvoke.NTDSApi;
namespace Vanara.PInvoke.Tests;
[TestFixture()]
public class NTDSApiTests
{
public SafeDsHandle? hDs;
public string? dn;
[OneTimeSetUp]
public void _Setup()
{
dn = Environment.UserDomainName;
DsBind(null, dn!, out hDs).ThrowIfFailed();
}
[Test, TestCaseSource(typeof(TestCaseSources), nameof(TestCaseSources.AuthCasesFromFile))]
public void DsBindTest(bool validUser, bool validCred, string urn, string dn, string dcn, string domain, string un, string pwd, string notes)
{
Assert.That(DsBind(dcn, dn!, out var dsb).Succeeded && !dsb.IsInvalid, Is.EqualTo(validUser));
Assert.That(DsBind(dcn, null, out var dsb1).Succeeded && !dsb1.IsInvalid, Is.EqualTo(validUser));
Assert.That(DsBind(null, dn!, out var dsb2).Succeeded && !dsb2.IsInvalid, Is.EqualTo(validUser));
}
[Test, TestCaseSource(typeof(TestCaseSources), nameof(TestCaseSources.AuthCasesFromFile))]
public void DsBindByInstanceTest(bool validUser, bool validCred, string urn, string dn, string dcn, string domain, string un, string pwd, string notes)
{
Assert.That(DsBindByInstance(DnsDomainName: dn!, AuthIdentity: SafeAuthIdentityHandle.LocalThreadIdentity, phDS: out var dsb).Succeeded && !dsb.IsInvalid, Is.EqualTo(validUser));
}
[Test]
public void DsBindToISTGTest()
{
Assert.That(DsBindToISTG(null, out var dsb).Succeeded && !dsb.IsInvalid, Is.True);
}
[Test, TestCaseSource(typeof(TestCaseSources), nameof(TestCaseSources.AuthCasesFromFile))]
public void DsBindWithCredTest(bool validUser, bool validCred, string urn, string dn, string dcn, string domain, string un, string pwd, string notes)
{
void Meth()
{
DsMakePasswordCredentials(un, dn!, pwd, out var cred).ThrowIfFailed();
DsBindWithCred(dcn, dn!, cred, out var hDs).ThrowIfFailed();
}
if (!validUser || !validCred)
Assert.That(Meth, Throws.Exception);
else
Assert.That(Meth, Throws.Nothing);
}
[Test, TestCaseSource(typeof(TestCaseSources), nameof(TestCaseSources.AuthCasesFromFile))]
public void DsCrackNamesTest(bool validUser, bool validCred, string urn, string dn, string dc, string domain, string un, string pwd, string notes)
{
var res = DsCrackNames(hDs!, new[] {un}, DS_NAME_FORMAT.DS_NT4_ACCOUNT_NAME);
Assert.That(res, Has.Exactly(1).Items);
for (var i = 0; i < res.Length; i++)
TestContext.WriteLine($"{i}) {res[i]}");
}
[Test]
public void DsSpnTest()
{
const string spn = @"MyService/host1.contoso.com:80/CN=Server1,OU=Servers,DC=Contoso,DC=com";
uint szSC = 1, szSN = 1, szIN = 1, szSPN = 0;
var tmp = new StringBuilder(1);
var ret = DsCrackSpn(spn, ref szSC, tmp, ref szSN, tmp, ref szIN, tmp, out var port);
StringBuilder sSC = new((int)szSC), sSN = new((int)szSN), sIN = new((int)szIN);
ret = DsCrackSpn(spn, ref szSC, sSC, ref szSN, sSN, ref szIN, sIN, out port);
ret.ThrowIfFailed();
ret = DsMakeSpn(sSC.ToString(), sSN.ToString(), sIN.ToString(), port, null, ref szSPN, null);
var sSPN = new StringBuilder((int)szSPN);
ret = DsMakeSpn(sSC.ToString(), sSN.ToString(), sIN.ToString(), port, null, ref szSPN, sSPN);
ret.ThrowIfFailed();
Assert.That(sSPN.ToString(), Is.EqualTo(spn));
uint uSpn = 1;
ret = DsGetSpn(DS_SPN_NAME_TYPE.DS_SPN_NB_HOST, "cxhndl", null, 0, 0, null, null, ref uSpn, out var hA);
ret.ThrowIfFailed();
DsFreeSpnArray(uSpn, hA);
}
[Test]
public void DsGetDCInfoTest()
{
DS_DOMAIN_CONTROLLER_INFO_1[]? s1 = null;
Assert.That(() => s1 = DsGetDomainControllerInfo<DS_DOMAIN_CONTROLLER_INFO_1>(hDs!, dn!), Throws.Nothing);
Assert.That(s1, Is.Not.Null.And.Property("Length").GreaterThan(0));
Assert.That(s1![0].fDsEnabled);
DS_DOMAIN_CONTROLLER_INFO_2[]? s2 = null;
Assert.That(() => s2 = DsGetDomainControllerInfo<DS_DOMAIN_CONTROLLER_INFO_2>(hDs!, dn!), Throws.Nothing);
Assert.That(s2, Is.Not.Null.And.Property("Length").GreaterThan(0));
Assert.That(s2![0].fDsEnabled);
DS_DOMAIN_CONTROLLER_INFO_3[]? s3 = null;
Assert.That(() => s3 = DsGetDomainControllerInfo<DS_DOMAIN_CONTROLLER_INFO_3>(hDs!, dn!), Throws.Nothing);
Assert.That(s3, Is.Not.Null.And.Property("Length").GreaterThan(0));
Assert.That(s3![0].fDsEnabled);
foreach (var i3 in s3)
TestContext.WriteLine($"{(i3.fIsPdc?"PDC":"DC")}{(i3.fIsGc?",GC":"")}{(i3.fIsRodc?",RO":"")}:\t{i3.NetbiosName}\t{i3.DnsHostName}\t{i3.SiteName}\t{i3.SiteObjectName}\t{i3.ComputerObjectName}\t{i3.ServerObjectName}\t{i3.NtdsDsaObjectName}\t{(i3.fDsEnabled?"Enabled":"Disabled")}");
}
[Test]
public void DsListRolesTest()
{
TestNameResult((SafeDsHandle h, out SafeDsNameResult nr) => DsListRoles(h, out nr), "Roles");
}
[Test]
public void DsListDomainsInSiteTest()
{
var site = TestNameResult((SafeDsHandle h, out SafeDsNameResult nr) => DsListSites(h, out nr), "Sites");
var dom = TestNameResult((SafeDsHandle h, out SafeDsNameResult nr) => DsListDomainsInSite(h, site, out nr), "Domains");
var siteserver = TestNameResult((SafeDsHandle h, out SafeDsNameResult nr) => DsListServersInSite(h, site, out nr), "SiteServers");
var dserver = TestNameResult((SafeDsHandle h, out SafeDsNameResult nr) => DsListServersForDomainInSite(h, dom, site, out nr), "DomServers");
var item = TestNameResult((SafeDsHandle h, out SafeDsNameResult nr) => DsListInfoForServer(h, dserver, out nr), "SvrInfo");
}
private delegate Win32Error NRDel(SafeDsHandle h, out SafeDsNameResult nr);
private string TestNameResult(NRDel f, string prefix)
{
var err = f(hDs!, out var hnr);
Assert.That(err, Is.EqualTo(Win32Error.ERROR_SUCCESS));
var nrs = hnr.ToArray();
Assert.That(nrs.Length, Is.Not.Zero);
var nr = nrs[0];
Assert.That(nr.pName, Is.Not.Null);
TestContext.WriteLine(prefix + ": " + string.Join(", ", nrs));
TestContext.WriteLine();
return nr.pName;
}
[Test]
public void DsGetRdnTest()
{
var ret = DsGetRdnW("dc=corp,dc=fabrikam,dc=com", out var dn, out var key, out var val);
ret.ThrowIfFailed();
Assert.That(dn!, Is.EqualTo(",dc=fabrikam,dc=com"));
Assert.That(key, Is.EqualTo("dc"));
Assert.That(val, Is.EqualTo("corp"));
}
[Test]
public void DsMapSchemaGuidsTest()
{
var guid = new Guid("2BEC133B-AE2B-4C32-A3F5-036149C4E671");
var err = DsMapSchemaGuids(hDs!, 1, new[] { guid }, out var map);
Assert.That(err, Is.EqualTo(Win32Error.ERROR_SUCCESS));
var items = map.GetItems(1);
var item = items[0];
Assert.That(item.guid, Is.EqualTo(guid));
}
[Test]
public void DsQuerySitesByCostTest()
{
var err = DsBindToISTG(null, out var hDs);
Assert.That(err, Is.EqualTo(Win32Error.ERROR_SUCCESS));
err = NetApi32.DsGetSiteName(null, out var hSiteName);
Assert.That(err, Is.EqualTo(Win32Error.ERROR_SUCCESS));
var site = hSiteName.ToString();
var sites = GetAllSiteNames();
err = DsQuerySitesByCost(hDs!, site, sites, (uint)sites.Length, 0, out var hnr);
Assert.That(err, Is.EqualTo(Win32Error.ERROR_SUCCESS));
var nrs = hnr.GetItems(sites.Length);
Assert.That(nrs.Length, Is.EqualTo(sites.Length));
var nr = nrs[0];
Assert.That(nr.cost, Is.Not.Null);
for (var i = 0; i < sites.Length; i++)
TestContext.WriteLine($"{sites[i]}: {(nrs[i].errorCode == Win32Error.ERROR_SUCCESS ? nrs[i].cost.ToString() : "Not found")}");
}
private static string[] GetAllSiteNames()
{
var rootDSE = new DirectoryEntry("LDAP://RootDSE");
var configNC = new DirectoryEntry("LDAP://" + rootDSE.Properties["configurationNamingContext"][0]);
var sitesContainer = new DirectoryEntry("LDAP://CN=Sites," + configNC.Properties["distinguishedName"][0]);
var siteFinder = new DirectorySearcher(sitesContainer, "(objectClass=site)") { PageSize = 100 };
using var results = siteFinder.FindAll();
return results.Cast<SearchResult>().Select(r => r.Properties["name"][0].ToString()).WhereNotNull().ToArray();
}
}