C# Inconsistent Security Group Membership - c#

I apologize for how open ended I'm sure this will end up. I'll try to break this up in manageable chunks.
I'm writing a program that deals with SCCM. This program is locked down by security groups.
If you are not a member of the 'Server Operators' group, you don't get in. Simple. I've been testing for awhile on my dev machine (a Dell that is on wireless) with no issues.
When I released a beta, I found that under certain circumstances the program will not pick up on the user's security group membership and therefore deny access.
I was able to reproduce the issue, it seems machines on wireless tend to have this issue. Though, it's more complicated than that.
-Freshly imaged machines seem to have this issue
-Not all wireless machines; my dev machine is wireless
-One desktop (no wireless) has this issue. (It's at a remote site, so I can't really pick that one apart) I think it's a fresh image as well. I did however test on another computer at the same site - worked fine.
-Connecting to ethernet seems to have an effect - 75% of the time it fixes the issue somehow - after a bit of a wait. (Works on both ethernet and wireless at that point)
I've been trying to get a breakpoint set on one of these machines so I can see what is going on. Problem is, by the time I get VS.net installed the problem solves itself. I know (very little) about remote debugging - currently looking into that. This scenario makes me wonder if it's update related (the image is fairly up to date, maybe a month or two out?)
I also wrote a small utility that tests the login procedure (using the same code) and it finds the security group every time. Wat.
Code for finding security group of a user:
(courtesy of Stack :) )
static bool IsUserMemberOf_(string user, string group)
{ // (I realize the user parameter is superfluous in this case)
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + TC.act_Domain, TC.act_AD_User, TC.enc_GetADPassword());
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=user)(|(cn=" + TC.act_AD_User + ")(sAMAccountName=" + TC.act_AD_User + ")))";
SearchResult result = mySearcher.FindOne();
foreach (string GroupPath in result.Properties["memberOf"])
{
if (GroupPath.Contains(group))
{
return true;
}
}
}
catch (DirectoryServicesCOMException)
{
}
return false;
}
I've also tried another method (using Principal.IsMemberOf() ), which had the same result. I've also investigated DNS/Network problems. Not ruling it out, but doesn't seem to be a factor in the testing I've done.
I'm at a loss. If anyone has any thoughts, by all means please lay them on me.
Thanks

Yeah, it was the .net version. Our image starts with .net 4.0. Throwing 4.5.2 at it clears it right up. I would have expected an error at runtime, but I guess not.
... I'll show myself out

Related

c# Change AD password Directoryservices

Im trying to get the following code to work, problem is, sometimes it does, sometimes it doesnt.
when it fails it gives the error 0x800704F1 "the system cannot contact a domain controller to service the authentication request"
I'd say about 90% of the time it fails.
I have tried giving it a static DC by adding it behind the contexttype this sadly did not help.
On an admin user it works always.. however i do believe users are supposed to be able to change their own password.
The error is triggered on the user.changepassword line
I hope someone else has a bright idea.
using (var context = new PrincipalContext(ContextType.Domain))
{
using (var user = UserPrincipal.Current)
{
try
{
user.ChangePassword(txt_old.Text, txt_new.Text);
user.Save();
}
catch(Exception p)
{
if (p.HResult.Equals("0x800708C5"))//Not secure enough according to password policy
{
MessageBox.Show("Volgens het systeem is uw nieuwe wachtwoord niet veilig genoeg, voldoet het aan alle eisen?", "Niet gelukt", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
else if (p.HResult.Equals("0x80070056")) //Wrong current password
{
MessageBox.Show("U heeft een verkeerd huidig wachtwoord ingevult, probeer het nogmaals", "Verkeerd wachtwoord", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
else if (p.InnerException.ToString().Contains("0x80070775")) //Temporarly locked out.
{
MessageBox.Show("Uw account is tijdelijk vergrendeld door te veel pogingen tot in te loggen met een foutief wachtwoord. Probeer het over 15minuten nogmaals of neem contact op met de helpdesk.", "vergrendeld.", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
else
{
MessageBox.Show(System.Security.Principal.WindowsIdentity.GetCurrent().Name + Environment.NewLine + p.HResult + Environment.NewLine + p.Message);
return;
}
}
}
}
The two Windows updates 3177108 and 3167679 have changed the behavior of ChangePassword.
There is a thread here about the issue: https://social.msdn.microsoft.com/Forums/vstudio/en-US/77dc733e-a13d-4349-9088-8065b85d5c3f/userprincipalchangepassword-stops-working-after-windows-updates-3177108-and-3167679?forum=netfxbcl
It seems, that you now have to specify a valid UPN when creating the PrincipalContext.
Before you could use a IP as endpoint when creating the context, now it seems it has to be a correct domain name aswell.
Furthermore, you now always receive the same exception when an error occurs - we used to receive the password policy exception for users choosing insufficient passwords, now we get:
System.DirectoryServices.AccountManagement.PrincipalOperationException:
The system cannot contact a domain controller to service the
authentication request. Please try again later. (Exception from
HRESULT: 0x800704F1)
UPDATE 04-10-2016:
The exception displayed above is really the general/generic error received for just about anything when calling ChangePassword after the updates.
If for instance some of the ports involved in the protocol is blocked by a firewall, you get this one as well (applicable if you call from a server/machine that is not domain joined).
Good resource for required ports: https://technet.microsoft.com/en-us/library/dd772723(v=ws.10).aspx
Note that the dynamic range is required as well.
If the user is not allowed to change password (domain policy, circumvent by setting MUST CHANGE AT NEXT LOGON FLAG) you also receive this exception.
Your problem may be that a password policy violation has occurred. That is, for example, if you have a password policy in place where users can't change their passwords to be one of their last 5, as an example, if they try to change to one of their last 5 you'll see this error thrown in my experience.
The error just before the exception you report (in my case) looks like this:
TargetInvocationException: COM error attempting to change an Active Directory password..
So i'd check your password policies and make sure that your users in these cases aren't violating it.
UPDATE: 10/12/2016:
Microsoft has updated this article: https://support.microsoft.com/en-us/kb/3177108 . Here they have given us problems created by the original "fixes" as well as some tips for working with Kerberos and self-service password reset.
As of October 11, 2016 Microsoft re-released the patches associated with https://technet.microsoft.com/en-us/library/security/ms16-101.aspx to resolve issues caused by the original updates (which you can read in https://support.microsoft.com/en-us/kb/3177108 including the fact that you could no longer change passwords on local accounts).
I believe I have the answer. Microsoft recently patched Windows so that NTLM can't be used to change passwords anymore.
Solution #1 (the "hammer"):
Try removing either one or both of these KB updates on your server running the code.
https://support.microsoft.com/en-us/kb/3177108
https://support.microsoft.com/en-us/kb/3167679
When you say you can change the password as an admin, do you mean only when your forms application is running on an admin's machine? Is the challenge when the application is running on a non-admin's machine?
I was able to take your code and get it work as is as well as changing the following:
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, "test.user0001"))
and
using (var user = UserPrincipal.FindByIdentity(context, IdentityType.UserPrincipalName, "test.user0001#webactivedirectory.com"))
Using either one of these lines as well as yours (getting the current user) I was able to change admin and non-admin passwords alike. My question is whether your error happens when you have the forms app running on a non-admins machine.
I witnessed this from the sysadmin side on two different occasions: two applications with password management features had to be installed on two freshly deployed servers, which had of course been fully patched; in both cases, changing passwords failed with an error about the application being unable to contact a domain controller (which, of course, was actually there and available).
One application was a closed-source vendor-supplied one (CyberArk's Privileged Session Manager), while the other one was an in-house application developed by the customer where I'm currently working; in the second case, I was able to take a look at the code, which was indeed similar to that used in the original question.
Sadly, actually fixing the code was not an option in both cases: for the first application we had to report a bug to the application vendor, while for the second one we had to report a bug to the internal development team working on the application, be we couldn't get an immediate fix in either case. Management wanted both applications working now, thus we had to remove the offending updates (I know, this is bad and not a solution but a lazy and dangerous workaround, and I tried all I could to avoid that; but management is management, so... meh).
Anyway, the reason I'm jumping in with this answer: apart from removing KB3177108 and KB3167679, in my case (both cases) we also had to remove KB3175024 and KB3174644; while those two updates were installed, the password change function still refused to work, even after removing the first two ones.
So, if you find yourself in a situation where you can't fix the code, and removing KB3177108 and KB3167679 doesn't solve the issue, then you can try removing also KB3175024 and KB3174644.

How do I resolve this error adding a new performance category in windows 7

I am trying to write some c# code that writes a new Performance Counter Category if it doesn't exist, and then adds a specific counter. When I run this code from the Visual Studio dev server, everything works fine. When I deploy it to IIS and try it, I get permission errors. I am running Windows 7 and using IIS 7.5.
What I have done so far, some of which is being done out of desperation:
Created a new App Pool that I will run as a specific user
Created a new user and added him to the Process Monitor and Administrator groups
Set the new user as the identity of the new App Pool
Pointed my web service to that App Pool.
Went in to regedit and gave the user full control over HKLM/System/CurrentControlSet (apparently there should be a permissions folder, but I don't see it anywhere).
I know these steps have worked partially, because I am now able to check whether or not a category exists (ASPNET user couldn't even do that). I can check if a category exists, I just cant add a new one.
The error that I get is
Cannot create or delete the Performance Category 'C:\Windows\TEMP\tmp1AA8.tmp' because access is denied.
The code to add the performance counter category is looks like this:
if (!PerformanceCounterCategory.Exists("APIService"))
{
CounterCreationDataCollection counters = new CounterCreationDataCollection();
CounterCreationData counter = new CounterCreationData();
counter.CounterName = "# of operations executed";
counter.CounterHelp = "Operations executed";
counter.CounterType = PerformanceCounterType.RateOfCountsPerSecond32;
counters.Add(counter);
PerformanceCounterCategory.Create("APIService", "Api Counter", PerformanceCounterCategoryType.SingleInstance, counters); // This code blows up
}
I have searched high and low and cant find anyone with the same problem. I have even tried giving Everyone Full Control over c:\windows\temp. Any idea what I might be missing here?
I think I figured out the solution (or rather someone else did, but I can find a link to that forum this morning). Instead of setting the App Pool to run as an admin, I switched it to the Local System user. That seems to have resolved everything, as the user has sufficient rights to write performance metrics and everything else that needs to be done.

Troubleshooting intermittent "No OpenID endpoint found" messages with Google and DotNetOpenAuth

I've been troubleshooting this one off and on for the past week. I've got a site using relying party MVC code from the DotNetOpenAuth project. I've been using this since 2009.
Recently, the Google logins have been failing. I'd say about 80% of the time the Google login works fine. So the intermittent nature makes this hard to diagnose.
Here's what I've tried:
Of course I've verified that the openid_identifier is using the correct URL ( https://www.google.com/accounts/o8/id )
I've updated to the latest release (DotNetOpenAuth 3.4).
I've tried adding default proxy settings as per this answer.
I've extended the timeout settings and even reduced memory on SQL to give IIS more RAM as this answer suggests.
I've added logging to every request and error to see if I could get any valuable information. This doesn't tell me much.
I've watched the requests/responses with Fiddler to see if I could spot anything.
I've tested my Google login on StackOverflow a number of times on the off chance that this is actually a problem with Google. And it's been working every time so far.
Any ideas?
UPDATE
In effort to pinpoint the problem I changed the code on my site a bit. Rather than doing this all on one line...
openid.CreateRequest(Request.Form["openid_identifier"]).RedirectingResponse.AsActionResult();
I broke it up into sections with logging in between...
MvcApplication.Logger.Info("Loading... " + Request.Form["openid_identifier"]);
var request = openid.CreateRequest(Request.Form["openid_identifier"]);
var redirect = request.RedirectingResponse;
MvcApplication.Logger.Info("Status... " + redirect.Status);
if (redirect.Status.ToString().ToLower() != "found")
{
MvcApplication.Logger.Error("Details... " + redirect.Body);
}
return redirect.AsActionResult();
So I'll be waiting for the next error.
I figured it out. This was being caused by New Relic. I'm not sure exactly how (or why it was intermittent) but that's what it was. New Relic automatically instruments your pages in certain ways so maybe it interfered with the request to the OpenID provider.
I looked back at the timeframe in which this all started and found that it was right around the time I installed New Relic on the server. So I uninstalled it, restarted IIS, and let the site go for 48 hours without it. I didn't get a single error in that time. So a couple hours ago I reinstalled it and sure enough I was able to duplicate the problem.
Anyway, I've removed New Relic again and all is good. I'll notify them about this.

Secure My ASP .NET Code For Presentation?

I have a web application , for presentation to my client they ask me to install it on their local server so they can test it , here is my question !?
Is there any way so i can publish uniquely for that server , i did put some limitation but many features in my app are open , so they can make a disk image from server and use it anywhere else ,
Is there any method to use so my web application check if this server is same server ( by hardware id or anything i don't have any idea ) then start to work !
I saw many codes but they are win forms for generating unique hid , but how can i connect done it with asp .net
EDIT
Could u take a look at this also ,
i am using system.management class
is this reliable i mean are they unique ?
private string GetUniqueID()
{
string cpuInfo = string.Empty;
ManagementClass mc = new ManagementClass("win32_processor");
ManagementObjectCollection moc = mc.GetInstances();
foreach (ManagementObject mo in moc)
{
if (cpuInfo == "")
{
//Get only the first CPU's ID
cpuInfo = mo.Properties["processorID"].Value.ToString();
break;
}
}
ManagementObject dsk = new ManagementObject(#"win32_logicaldisk.deviceid=""" + "C" + #":""");
dsk.Get();
string volumeSerial = dsk["VolumeSerialNumber"].ToString();
string HardWareUniqueID = volumeSerial + cpuInfo;
return HardWareUniqueID;
}
Appreciate your answers,
Thanks in advance
If you want to avoid having it "phone home" an alternative is to generate some kind of certificate and place it on the machine. Use a private key that only you know to encrypt the machine name and/or IP. Then have your app use your public key to decrypt it to verify that it is allowed to run on this server. Nobody who doesn't know your private key will be able to create valid certificates.
You hae a few choices...
Lock your web site to the single IP address you install it on. To make your life easier, check for that IP in a common page base class. (Note, you could also write HTTP handlers, but the base-class approach is easier.)
Put a 'phone home' call in the app that checks with your server every time it's started up. That way you can check if they have moved it or if multiple instances are running.
Use the built-in licensing features of .NET (the same one third-party developers use for controls, etc.)
The easiest... just put in a time-bomb that lets them test it for a few weeks, then automatically blocks access. Be smart though... persist the last-checked time so you can tell if they've rolled back their clock trying to get more usage.
Just make sure to distribute a web application, not a web project so you can distribute your code as a compiled bumary rather than having to ship the code-behind files. That will keep prying eyes out, but does make deployment more a pain since you always have to recompile with every change (as opposed to on-demand compiling.)
I would put in a time bomb. It's trivial to implement. Also, your client's won't think that you don't trust them. A fixed evaluation period in the application is extremely common.
Provide them a VMware image without any user-access just allow them to open the website externally via HTTP in their web browser.

Process.StartTime Access Denied

My code needs to determine how long a particular process has been running. But it continues to fail with an access denied error message on the Process.StartTime request. This is a process running with a User's credentials (ie, not a high-privilege process). There's clearly a security setting or a policy setting, or something that I need to twiddle with to fix this, as I can't believe the StartTime property is in the Framework just so that it can fail 100% of the time.
A Google search indicated that I could resolve this by adding the user whose credentials the querying code is running under to the "Performance Log Users" group. However, no such user group exists on this machine.
I've read something similar to what you said in the past, Lars. Unfortunately, I'm somewhat restricted with what I can do with the machine in question (in other words, I can't go creating user groups willy-nilly: it's a server, not just some random PC).
Thanks for the answers, Will and Lars. Unfortunately, they didn't solve my problem.
Ultimate solution to this is to use WMI:
using System.Management;
String queryString = "select CreationDate from Win32_Process where ProcessId='" + ProcessId + "'";
SelectQuery query = new SelectQuery(queryString);
ManagementScope scope = new System.Management.ManagementScope(#"\\.\root\CIMV2");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection processes = searcher.Get();
//... snip ... logic to figure out which of the processes in the collection is the right one goes here
DateTime startTime = ManagementDateTimeConverter.ToDateTime(processes[0]["CreationDate"].ToString());
TimeSpan uptime = DateTime.Now.Subtract(startTime);
Parts of this were scraped from Code Project:
http://www.codeproject.com/KB/system/win32processusingwmi.aspx
And "Hey, Scripting Guy!":
http://www.microsoft.com/technet/scriptcenter/resources/qanda/jul05/hey0720.mspx
Process of .Net 1.1 uses the Performance Counters to get the information. Either they are disabled or the user does not have administrative rights. Making sure the Performance Counters are enabled and the user is an administrator should make your code work.
Actually the "Performance Counter Users Group" should enough. The group doesn't exist by default. So you should create it yourself.
Process of .Net 2.0 is not depended on the Performance Counters.
See http://weblogs.asp.net/nunitaddin/archive/2004/11/21/267559.aspx
The underlying code needs to be able to call OpenProcess, for which you may require SeDebugPrivilege.
Is the process you're doing the StartTime request on running as a different user to your own process?
OK, sorry that didn't work... I am no expert on ASP.NET impersonation, I tend to use app pools which I don't think you can do on W2K Have you tried writing a tiny little test app which does the same query, and then running that as various users?
I am reluctant to post a chunk of MS framework code here, but you could use either Reflector or this: http://www.codeplex.com/NetMassDownloader to get the source code for the relevant bits of the framework so that you could try implementing various bits to see where it fails.
Can you get any other info about the process without getting Access Denied?
I can enumerate the process (ie, the GetProcessById function works), and we have other code that gets the EXE name and other bits of information.
I will give the test app a try. I'm also going to attempt to use WMI to get this information if I can't get the C# implementation working properly in short order (this is not critical functionality, so I can't spend days on it).

Categories

Resources