我构建了一个应用程序,可以帮助我完成一些任务,例如将用户添加到组、删除、创建用户、删除用户以及在 Active Directory 中解锁用户。这些都需要一些管理员权限。
目前,它验证管理员帐户连接到域的方式是基于密码的身份验证。
系统会提示用户提供用户名和密码,并使用
PrincipalContext
我对会话进行身份验证。在整个应用程序中,我引用 context
变量来执行这些任务。
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, _myDomainName, adminUsername, adminPassword))
我想检查应用程序的登录情况以使用智能卡。我能够使用它,但据我所知,
PrincipalContext
似乎只支持基于密码的身份验证,不支持基于证书的身份验证。这导致 context
变量无法在会话中引用我的管理员帐户,从而导致“访问被拒绝”错误。
目前我像这样验证用户身份:
static X509Certificate2 GetAdminCertificate()
{
Console.Write("Enter admin username: ");
adminUsername = Console.ReadLine().Trim();
/*
Console.Write("Enter your smart card PIN: ");
string smartCardPin = PasswordManager.GetPassword().Trim();
*/
using (X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadOnly);
X509Certificate2Collection yubiKeyCerts = new X509Certificate2Collection();
foreach (var cert in store.Certificates)
{
// First, check if the subject name matches the admin username
string subjectName = cert.GetNameInfo(X509NameType.SimpleName, false);
if (!subjectName.Equals(adminUsername, StringComparison.OrdinalIgnoreCase))
{
// Skip this certificate if the subject does not match
continue;
}
try
{
if (cert.HasPrivateKey)
{
// Access the private key
var privateKey = cert.PrivateKey;
if (privateKey is RSACng rsaCng)
{
if (rsaCng.KeyExchangeAlgorithm.Equals("RSA", StringComparison.OrdinalIgnoreCase))
{
// Match the certificate with admin username
if (subjectName.Equals(adminUsername, StringComparison.OrdinalIgnoreCase))
{
// Attempt to sign data with the RSA key to validate access
byte[] dataToSign = new byte[] { 0x01 }; // Dummy data
byte[] signedData = rsaCng.SignData(dataToSign, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
yubiKeyCerts.Add(cert);
} // end of if-statement
} // end of if-statement
} // end of if-statement
} // end of if-statement
} // end of try
catch (Exception ex)
{
Console.WriteLine($"Error obtaining certification: {ex.Message}");
continue;
} // end of catch
} // end of foreach
if (yubiKeyCerts.Count == 0)
{
Console.WriteLine("No smart card detected or no valid certificates found on the connected smart card.");
return null;
}
// X509Certificate2 selectedCert = null;
if (yubiKeyCerts.Count > 0)
{
selectecdCert = X509Certificate2UI.SelectFromCollection(
yubiKeyCerts,
"Select a YubiKey certificate",
"Please select your admin certificate from the YubiKey",
X509SelectionFlag.SingleSelection
)[0];
}
adminUsername = selectecdCert.GetNameInfo(X509NameType.SimpleName, false);
// adminPassword = selectecdCert.Verify();
return selectecdCert;
} // end of using x509Store
} // end of GetAdminCertificate
(太多 if 语句 - 我知道)
应用程序通过以下方式连接到域:
static void Main(string[] args)
{
ActiveDirectoryManager ADManager = new ActiveDirectoryManager();
AccountCreationManager ACManager;
AccountDeactivationManager ACCDeactivationManager = new AccountDeactivationManager();
PasswordManager PWDManager = null;
ADGroupActionManager ADGroupManager = null;
AuditLogManager auditLogManager = null;
configuration = new ConfigurationBuilder()
.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("Appsettings.json", optional: false, reloadOnChange: true)
.Build();
EmailNotifcationManager emailManager = new EmailNotifcationManager(configuration);
string _myDomainName = configuration["AccountCreationSettings:myDomainName"];
do
{
X509Certificate2 certificate = GetAdminCertificate();
if (certificate == null)
{
Console.WriteLine("No valid smart card certificate found.");
return;
}
try
{
using (PrincipalContext context = new PrincipalContext(ContextType.Domain, _myDomainName))
// Check if the the password/user are correct
{
// Throw error if the password/username is incorrect
if (context.ConnectedServer != null)
{
isAuthenticated = true;
Console.WriteLine($"Connected to Active Directory as: {adminUsername}.".Pastel(Color.GreenYellow));
auditLogManager = new AuditLogManager(adminUsername, configuration);
ADGroupManager = new ADGroupActionManager(auditLogManager);
PWDManager = new PasswordManager(auditLogManager);
ACManager = new AccountCreationManager(auditLogManager, configuration);
bool exit = false;
// Loop the menu
while (!exit)
{
DisplayMainMenu();
string choice = Console.ReadLine();
exit = HandleMainMenuChoice(choice, context, ADManager, ADGroupManager, PWDManager, ACManager, ACCDeactivationManager);
} // end of while-loop
} // end of if statement
context.Dispose();
} // end of using
} // end of try
catch (DirectoryServicesCOMException)
{
// Error out if password/username are incorrect
Console.WriteLine("Error: Unable to connect to the Active Directory server. Please check your credentials and try again.".Pastel(Color.IndianRed));
}
catch (Exception ex)
{
Console.WriteLine($"An error occurred: {ex.Message}".Pastel(Color.IndianRed));
} // end of Catch
} while (!isAuthenticated || string.IsNullOrEmpty(adminUsername));
// Repeat until a valid password is entered
} // end of Main Method
访问被拒绝的代码片段示例。正如您所看到的,我在此处引用了
context
变量来使用管理会话来执行这些任务。
UserPrincipal user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username);
// Check for user in AD
if (user != null)
{
// Check for group in AD
GroupPrincipal group = GroupPrincipal.FindByIdentity(context, groupName);
if (group != null)
{
// If the user is not in the group add him
if (!group.Members.Contains(user))
{
// Add the user to the group
group.Members.Add(user);
// Apply changes
group.Save();
group.Dispose();
Console.WriteLine($"User '{username}' added to group '{groupName}' successfully.".Pastel(Color.LimeGreen));
string logEntry = ($"\"{user.DisplayName}\" has been added to \"{groupName}\" group in Active Directory\n");
emailActionLog.Add(logEntry);
auditLogManager.Log(logEntry);
} // end of inner-2 if-statement
else
{
Console.WriteLine($"User '{username}' is already a member of group '{groupName}'.".Pastel(Color.DarkGoldenrod));
} // end of inner-2 else-statement
} // end of inner if-statement
else
{
Console.WriteLine($"Group '{groupName}' not found in Active Directory.".Pastel(Color.IndianRed));
} // end of outer else-statement
}
我的主要问题是,有没有一种方法可以通过基于认证的登录来验证我的管理员帐户?
您可以;
设置证书颁发机构 (CA) 并颁发智能卡证书或
从第三方证书提供商获取智能卡证书
在第一个选项中,如果您设置了 Microsoft CA,它可以颁发智能卡证书,您可以直接使用该证书登录 AD(Active Directory)域,它会将 CA 视为受信任的根权限并自动映射 UPN(用户主体)名称)证书的一部分(应位于 CN 字段)给 AD 用户。
在第二个选项中,您应该将提供商的根 CA 分发到客户端 PC,并按照以下步骤进行操作 https://learn.microsoft.com/en-us/troubleshoot/windows-server/certificates-and-public-密钥基础设施-pki/导入第三方-ca-至企业-ntauth-store。智能卡登录需要此过程。
在这两个选项中,应用程序将运行的客户端 PC 都应该是 AD 域成员。
在您的应用程序中,我认为您应该检查CN(通用名称)字段中的UPN信息,并检查智能卡证书链的根证书是否受到操作系统的信任。那么 UPN 可能应该映射到 AD 用户。