UserPrincipal.Current throws COMException from one day to the next - c#

This morning I started noticing some problems with several of my programs regarding Active Directory read operations. I noticed that all those applications (client and server) use the System.DirectoryServices.AccountManagement.UserPrincipal class for those read operations, while the programs still running correctly use System.DirectoryServices.DirectorySearcher.
So in order to narrow the problem down, I built the following, very simple console application
class Program
{
static void Main(string[] args)
{
//this works great
Console.WriteLine($"Enviroment.Username:{Environment.UserName}");
//this works great
PrincipalContext pcFull = new PrincipalContext(ContextType.Domain, "my.company.de", "dc=my,dc=company,dc=de");
UserPrincipal upPrincipalContextFull = UserPrincipal.FindByIdentity(pcFull, Environment.UserName);
//this doesn't work at all
//Exception: “The specified directory service attribute or value does not exist”
PrincipalContext pc = new PrincipalContext(ContextType.Domain);
UserPrincipal upPrincipalContext = UserPrincipal.FindByIdentity(pc, Environment.UserName);
//this doesn't either, same exception
UserPrincipal upCurrent = UserPrincipal.Current;
Console.ReadKey();
}
}
As you can see in the comments, the two latter operations will fail on every Computer in the domain i tested it on, even though they worked perfectly for several years. The following Exception occurs when I call UserPrincipal.Currentor UserPrincipal.FindByIdentity(pc, Environment.UserName); without specifying the Container in the PrincipalContext:
System.Runtime.InteropServices.COMException: “The specified directory service attribute or value does not exist”
Here is what I know:
none of the applications that suddenly stopped working received an update within the last two weeks
all of those applications, the UserPrincipal.Current-Property and the UserPrincipal.FindByIdentity-Method worked perfectly yesterday
Workstations did not receive Windows or .Net updates in the last week
the phenomenon does not relate to a single workstation, user or OS, but occures for a lot of different users, on a lot of different machines running Windows 7 or 10.
Domain Controllers received updates a week ago. Apparently one of those updates has a known issue about LDAP queries: Due to a defect in WLDAP32.DLL, applications that perform LDAP referral chasing can consume too many dynamic TCP ports. It seems unlikely that this is the reason for the sudden failures because a) that patch was installed a week ago and the Problems only occurred today and b) the suggested Workarounds from Microsoft (restarting Services) don't have any effect
What might cause such a behavior "overnight"? If it really is related to a Windows update, other users will soon be experiencing this bug too!
I can obviously build Workarounds, so I don't have to use the failing methods and properties, but I still have to know why it stopped working in the first place.
Edit
To start with, it would be useful to understand the difference between
public PrincipalContext(ContextType contextType); and public PrincipalContext(ContextType contextType, string name, string container);. The PrincipalContext constructed without container still has to obtain that container somehow, doesn't it?

By default the PrincipalContext searches in the "OU=Computers"-Container.
This fails if the reading permission is not set for the Container and will throw a COM Exception.

Related

C# EventLog.Delete Access Denied

I have read other questions on SO in regards to security and registry keys, nothing has helped me solve my particular use case scenario.
Here's my scenario:
What I'm Trying To Do
I want to, in code, delete a windows event log.
The Problem
When executing the function, I receive a System.ComponentModel.Win32Exception. The exception message is "Access is denied".
How I Am Doing It Currently
I am using an impersonator function that I wrote which wraps around the EventLog.Delete function, it drops me into a user context that has full access to the EventLog Registry Hive. Subsequently the logs I am interested in also have full access for this particular user.
My Question
Why do I receive a "Access Is Denied" if the user I am running under (through impersonation) has full access to the log in question? I've tested my Impersonation function and it works as expected for other code I've written. I don't get why I would get access denied for this.
In another scenario with my impersonation function it works just fine, for example if I tried to write to a file that the user context that is running the program does not have write access to, then I would not be able to write to the text file, however if I use my impersonation to drop into a user context that does have write access then it works just fine (I can write to the file). So I just don't understand why the same concept can't be applied to registry keys.
What am I missing here?
The Code
Exception Message
My Test
Where sw-test is a user I created for testing purposes, it has full access permissions to the registry we are trying to delete.
[TestMethod]
public void DeleteEventLog_ValidatedUser_DeleteLog()
{
using (new Impersonator(Environment.UserDomainName, "sw-test", "pswd"))
{
Logging logging = new Logging();
logging.DeleteEventLog("testLog");
}
}
Okay I eventually got around to figuring this out, there were two issues at play here that were causing the mentioned exception being thrown, they are as follows:
1. Visual Studio was NOT running in administrator mode.
Not running visual studio in administrator mode was one part of the problem, this seems to be associated with access tokens in the windows OS. According to a source I read, if I run a program without UAC on (which is my scenario, I have it off), then the program being run gets a copy of my access token. However if I have UAC enabled, the program gets a copy of my access token but it is a restricted access token. (see: What precisely does 'Run as administrator' do?) - To be honest this doesn't really make sense in my case, why do I have to run as admin if I have UAC off? Shouldn't visual studio have an unrestricted copy of my access token? I am in the administrator group with UAC off...
2. Not Specifying NewCredentials As a Logon32Type In Impersonation
I don't really understand it but as soon as I specified this for my impersonation everything started working perfectly, I read a blog about it, it talks about how it was introduced in the VISTA days and how it was mainly used to specify credentials to outbound network connections to servers, and was mainly used to remedy security-related issues server-side. Don't see how it correlates to interfacing with local event logs though. (see: https://blogs.msdn.microsoft.com/winsdk/2015/08/25/logonuser-logon32_logon_new_credentials-what-is-this-flag-used-for/)
Code
using (new Impersonator(Environment.UserDomainName, "sw-test", "pswd", Advapi32.Logon32Type.NewCredentials))
{
EventLog.CreateEventSource("testSource", "testLog");
EventLog.Delete("testLog");
}
Where the NewCredentials is an int 9

Connection errors after project moved to a new server

I have been experiencing run-time errors in my application since the project files were moved to a new file server this past weekend as well the retirement of several old domain controllers. One is an LdapException (The connection cannot be established) when creating a new PrincipalContext as in the code below:
WindowsPrincipal wp = new WindowsPrincipal(WindowsIdentity.GetCurrent());
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain))
{
UP = UserPrincipal.FindByIdentity(pc, wp.Identity.Name);
}
I've tried a number of things including specifying various domain names and my network administrator has tried several things, but no luck.
I am also receiving an EntityException (The underlying provider failed on Open) when trying to get data from my MySQL database using EF as in the following code (crashes on the second line).
p = new pEntities();
Statuses = new ObservableCollection<status>(p.statuses);
I've taken several drastic steps that haven't solved my issues:
Uninstalled and reinstalled Visual Studio
Uninstalled and reinstalled MySQL
Deleted my user profile (this fixed some errors I was getting in VS, but not he run-time errors in the application itself)
I've tested the code in a completely new project and get the same errors, so it doesn't seem related to the project itself. I've also read quite a few SO and other posts on the two errors, but haven't been able to figure anything out. Is there something else I should be doing?
UPDATE
So, I moved my project to a local drive (C:) rather than the network, and now both errors are resolved, but I have no idea why that would fix it. Are there any known issues with running projects from networks drives that could cause these types of errors?

Converting Microsoft EWS StreamingNotification Example to a service

I've been working to try and convert Microsoft's EWS Streaming Notification Example to a service
( MS source http://www.microsoft.com/en-us/download/details.aspx?id=27154).
I tested it as a console app. I then used a generic service template and got it to the point it would compile, install, and start. It stops after about 10 seconds with the ubiquitous "the service on local computer started and then stopped."
So I went back in and upgraded to C# 2013 express and used NLog to put a bunch of log trace commands to so I could see where it was when it exited.
The last place I can find it is in the example code, SynchronizationChanges function,
public static void SynchronizeChanges(FolderId folderId)
{
logger.Trace("Entering SynchronizeChanges");
bool moreChangesAvailable;
do
{
logger.Trace("Synchronizing changes...");
//Console.WriteLine("Synchronizing changes...");
// Get all changes since the last call. The synchronization cookie is stored in the
// _SynchronizationState field.
// Only the the ids are requested. Additional properties should be fetched via GetItem
//calls.
logger.Trace("Getting changes into var changes.");
var changes = _ExchangeService.SyncFolderItems(folderId, PropertySet.IdOnly, null, 512,
SyncFolderItemsScope.NormalItems,
_SynchronizationState);
// Update the synchronization cookie
logger.Trace("Updating _SynchronizationState");
the log file shows the trace message ""Getting changes into var changes." but not the "Updating _SynchronizationState" message.
so it never gets past var changes = _ExchangeService.SyncFolderItems
I cannot for the life figure out why its just exiting. There are many examples of EWS streaming notifications. I have 3 that compile and run just fine but nobody as far as I can tell has posted an example of it done as a service.
If you don't see the "Updating..." message it's likely the sync threw an exception. Wrap it in a try/catch.
OK, so now that I see the error, this looks like your garden-variety permissions problem. When you ran this as a console app, you likely presented the default credentials to Exchange, which were for your login ID. For a Windows service, if you're running the service with one of the built-in accounts (e.g. Local System), your default credentials will not have access to Exchange.
To rectify, either (1) run the service under the account you did the console app with, or (2) add those credentials to the Exchange Service object.

Getting Error Querying Active Directory On The Server Only

I have the following block of code that queries Active Directory for users by Group Name using System.DirectoryServices.AccountManagement:
var domainContext = new PrincipalContext(ContextType.Domain, "company.container.internal");
var groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, IdentityType.Name, "Lvl1Users");
if (groupPrincipal != null)
{
//Read the values
}
Now the site uses the following:
IIS7 on Win2k8
Windows Authentication
Impersonation = True
App Pool on .NET 4.0 using 'NETWORK SERVICE' as the account
On my local machine (you know how this goes) it all works great. My peers that try it locally also it works well. However once deployed to the server it shows the following:
An operations error occurred.
Everything I research says it's a permissions issue. 1 thing to note, on my local machine I'm on the MainNetwork domain which is the parent to company.container.internal domain which I am querying. The IIS machine is on company.container.internal and is querying the same domain. So honestly, I would think the more challenging situation is reading AD on my local machine which is on a different domain, but it works. On the server which is querying the same domain, it fails.
Here is what I've tried, and none of these has worked:
Change AppPool to 'LocalSystem'
Change AppPool to use a static super-duper Admin account
Used Impersonation in code to manipulate the context of the calls in a local block with an admin user on the MainNetwork domain.
Used Impersonation in code to manipulate the context of the calls in a local block with an admin user on the company.container.internal domain.
Adding in using (HostingEnvironment.Impersonate())
What gives here? I have tried impersonating every type of power admin on both domains, and used multiple AppPool settings, and I keep getting the same error. Is there anything that needs to change in the code with the declaration of the domains, or is there a permissions issue I'm missing?
I figured this out and it turned out that using HostingEnvironment.Impersonate() was still at the root to solve the problem. I had already tried this, but there was another issue with my code.
The issue is often that the context for which the Active Directory calls is made is under a user that does not have permissions (also can happen when identity impersonate="true" in ASP.NET, due to the fact that the users token is a "secondary token" that cannot be used when authenticating against another server from: http://bit.ly/1753RjA).
The following code will ensures that the block of code running, is run under the context of say the AppPool (i.e. NETWORKSERVICE) that the ASP.NET site is running under.
using (HostingEnvironment.Impersonate())
{
var domainContext = new PrincipalContext(ContextType.Domain, "myDomain.com");
var groupPrincipal = GroupPrincipal.FindByIdentity(domainContext, IdentityType.Name, "PowerUsers");
if (groupPrincipal != null)
{
//code to get the infomation
}
}
However, one super important detail is that all the code calling Active Directory must be in that block. I had used some code a team member of mine wrote that was returning a LINQ query results of type Users (custom class), but not evaluating the expression (bad practice). Therefore the expression tree was returned instead of the results.
What ended up happening is the calling code eventually evaluated the results and the An operations error occurred message still appeared. I though the code fix above didn't work. When in fact it did, but there was code evaluating the results outside the block.
In a nutshell, make sure all code to access Active Directory is inside that using block and the exception should be fixed one the service/app is deployed to the server.

GroupPrincipal.FindByIdentity Unknown COM Exception

When deploying this code to a web application where the identity is the app pool user the following code throws an unknown COM exception. The exception is happening when the FindByIdentity method is invoked.
System.Runtime.InteropServices.COMException: Unknown error
(0x8000500c)
using (PrincipalContext prinCon = new PrincipalContext(ContextType.Domain))
{
GroupPrincipal groupPrin = GroupPrincipal.FindByIdentity(prinCon, name);
}
If I change the application pool identity to a domain user this problem is resolved. Which initially leads me to believe it is a permission/security issue. However, this error does not happen on all servers, just some. Additionally, a restart will fix this issue.
So, my question is why would restarting the server fix this issue? And is there a way I make this work without restarting?
I've done a fair amount of googling and haven't come across anyone with the same problem, a few permission similar issues, but none that help solve my problem.
Thanks in advance.
Changing the app pool account is what worked for me. It was ApplicationPoolIdentity user, but after I changed to Network Service, this error went away and the AD code works fine. I hope this helps.
You didn't specify an identity type, but then you're feeding it a string. Perhaps its not knowing how to search for the string. For example, maybe it is assuming the string is a guid and then attempting to parse it and then failing.
Try something like:
var groupPrin = GroupPrincipal.FindByIdentity(prinCon, IdentityType.Name , name);
Also, try to set your PrincipalContext with some credentials that definitely have authority to perform these operations such as an admin or services account.

Categories