Changing AD User Account Property by using the UserPrincipal - c#

I am trying to change the User Account Property in Active Directory by using the UserPrincipal.
I have read that we have to use the special account which has the write access to the Active Directory rather than the current log on user. So, I created the special class to impersonate by using the Special Account. But I am still having the
System.UnauthorizedAccessException: General access denied error
at user.Save(ctx); line.
System.Security.Principal.WindowsImpersonationContext newUser = clsImpersonate.ImpersonateUser("ADUser", "ADPassword");
if (newUser != null)
{
PrincipalContext ctx = blAD.GetAdminPrincipalContext();
UserPrincipal user = blAD.GetUserPrincipal(this.SAMAccount);
user.Enabled = false;
user.Save(ctx);
newUser.Undo();
}
How can I achieve this requirement? Thanks.

What permissions have been delegated to your special user? It needs to be able to write userAccountControl on the users in question.

I wouldn't impersonate the account first off! Gain access through by passing the values through ad first.
For the real issue, look at the error:
Get the principalContect.
Get the userprincipal.
Do what you want to do.
Save it, why are u using undo? Delete the Undo().

To access the Principle as another user, define your PrincipalContext with the credentials of the user and use that PrincipalContext when getting the UserPrincipal.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "domain.tld", "ADUser", "ADPassword");
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, this.SAMAccount);
if (user != null)
{
user.Enabled = false;
user.Save();
}
If you are still getting the UnauthorizedAccess Exception, it is likely because the account you are specifying does not have access to write the userAccountControl attribute on the user object in Active Directory/LDS.

Related

UserPrincipal doesn't let me add new user

I'm having a bit of a problem when trying to add a new user or trying to access an already existing user in the Active Directory through my C# program.
var principalContext = new PrincipalContext(ContextType.Domain, "domain", "OU=Users,OU=SI");
UserPrincipal usr = UserPrincipal.FindByIdentity(principalContext, IdentityType.SamAccountName, samAccountStr);
It's throwing the "An operations error ocurred" exception. I found out that it's supposed to that if the user doesn't have the right permission for the Active Directory but I am running the program as administrator with the account of someone who can add users to the AD. So I really don't know what could be wrong. When I try to add a new user I try it like this:
var principalContext = new PrincipalContext(ContextType.Domain, "domain", "OU=Users,OU=SI");
UserPrincipal usr = new UserPrincipal(principalContext);
The code for the existing user already breaks when I call FindByIdentity. The code for the new user however breaks after I try to set some values for the new user principle. For example:
usr.Surname = sn;
The extended error says it's:
SvcErr: DSID-031007DF, problem 5012 (DIR_ERROR)
So any idea as to what might be causing it if it's not a permission problem?
You have to provide a full Distinguished Name for the OU, including the domain. This is not valid:
"OU=Users,OU=SI"
Something like this would be (if your domain was "domain.com"):
"OU=Users,OU=SI,DC=domain,DC=com"

Get WindowsPrincipal from UserPrincipal

The goal
I'm writing a class that abstracts various Windows user mechanics. My class knows about the user's account name and domain, if any. I am trying to hydrate a property that indicates whether the user has administrative privilege on either the domain or the local environment that it belongs to.
The problem
The WindowsPrincipal class provides that information via IsInRole, but it's constructor requires a WindowsIdentity, which I can't find a way to establish without a user principal name (UPN). The UserPrincipal.UserPrincipalName property is available for domain users, but null for local users. Is there another way to get a WindowsPrincipal from a UserPrincipal? Alternatively, is there another way to accomplish the goal without it?
The source
using (PrincipalContext principalContext = new PrincipalContext(PrincipalContextType, principalContextName))
{
using (UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(principalContext, IdentityType.Name, Name))
{
// Capture additional information from the user principal.
Certificates = userPrincipal.Certificates;
DisplayName = userPrincipal.DisplayName;
UserPrincipalName = userPrincipal.UserPrincipalName;
// This constructor blows up because UserPrincipalName is null for local users.
using (WindowsIdentity windowsIdentity = new WindowsIdentity(UserPrincipalName))
{
// Capture group membership information about the specified user.
WindowsPrincipal windowsPrincipal = new WindowsPrincipal(windowsIdentity);
// Determine if the user has administrative privilege on the domain or local machine.
HasAdministrativePrivilege = windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator);
}
}
}
Thanks in advance.

How to edit the registry keys of a specific user programatically?

I want to change a few settings of a Windows user that I created in my application. If I understand correctly, his "HKEY_CURRENT_USER" values will be under HKEY_USERS/<sid>/.... Is this correct? How can I get the sid of the user, if I know the user name and the domain?
Edit: How can I correctly edit the HKCU keys of that user, if I have the sid already?
I have a program that does exactly that. Here is the relevant part of the code:
NTAccount ntuser = new NTAccount(strUser);
SecurityIdentifier sID = (SecurityIdentifier) ntuser.Translate(typeof(SecurityIdentifier));
strSID = sID.ToString();
You will need to import two namespaces:
using System.DirectoryServices;
using System.Security.Principal;
Hope this helps.
Then use Registry.Users.SetValue with SID string\path to set the registry value.
This might not work as intended if you are editing a logged-off profile, especially a roaming profile.
There are two steps to this. First you must get the users sid. Second you must load the users registry hive. Other users hives are not loaded by default so you must load it explicitly.
The answer in Daniel White's comment is the best way to get the sid.
To load the user's registry hive, use the LoadUserProfile windows API via pinvoke. There is a complementary UnloadUserProfile to unload the hive when you are done with it.
You can use Query by example and search using PrincipalSearcher for appropriate UserPrincipal
// Since you know the domain and user
PrincipalContext context = new PrincipalContext(ContextType.Domain);
// Create the principal user object from the context
UserPrincipal usr = new UserPrincipal(context);
usr .GivenName = "Jim";
usr .Surname = "Daly";
// Create a PrincipalSearcher object.
PrincipalSearcher ps = new PrincipalSearcher(usr);
PrincipalSearchResult<Principal> results = ps.FindAll();
foreach (UserPrincipal user in results) {
if(user.DisplayName == userName) {
var usersSid = user.Sid.ToString();
}
}

AD Update email address using MembershipUser - Access denied

I am trying to provision some users to update their email address in active directory (AD). I'm trying to achieve it using MembershipUser class. But getting 'general access denied error'. Here's my code:
string userName = "sathish";
System.Web.Security.MembershipUser userDetails = System.Web.Security.Membership.GetUser(userName);
if (userDetails != null)
{
userDetails.Email = "sathish#xyzee.com";
System.Web.Security.Membership.UpdateUser(userDetails); // getting access denied error here
}
My question is,
Do I need proper previleges to update email address to AD?
Do we have any attribute to verify my current access level?
Is it possible to impersonate privileges programmatically to update email address?
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context for your current, default domain
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
// find user by name
string userName = "sathish";
UserPrincipal user = UserPrincipal.FindByIdentity(userName );
// if user is found - update it's e-mail address and save
if(user != null)
{
user.EmailAddress = "sathish#xyzee.com";
user.Save();
}
The new S.DS.AM makes it really easy to play around with users and groups in AD:

What is the best way to get the value of what user is logged in?

I have a Windows form application that users can log into. The application is alone and doesn't connect with anything or anyone.
Besides creating a global variable, how could I have an easily accesible variable to check the current users permissions?
A not so kosher way of doing things is just pass the ID of the userType in the Form constructor and according to that, .Enable = false; buttons they don't have permissions to use.
Thanks!
If you want the id of the currently logged on Windows user (ie. the user that the application is running as), there are two ways of getting it:
By putting AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal); in your startup, you can use Thread.CurrentPrincipal to get the user's security principal.
You can use WindowsIdentity.GetCurrent() to get the current user's identity. You can then create a security principal using new WindowsPrincipal(identity).
Both of these are equivalent, and will get you a security principal that has an IsInRole method that can be used to check permissions.
Use the WindowsIdentity class for getting the users Identity, found under System.Security.Principal.WindowsIdentity.
WindowsIdentity current = WindowsIdentity.GetCurrent();
Console.WriteLine("Name:" + current.Name);
Use the WindowsPrincipal class for getting the users Roles, found under System.Security.Principal.WindowsPrincipal.
WindowsIdentity current = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(current);
if (principal.IsInRole("your_role_here")
{
Console.WriteLine("Is a member of your role");
}

Categories