How to query AD to get name email from lan id - c#

I have some code in asp.net ( kindly given by someone else ) to query AD to get user name and email etc.
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
using ActiveDs;
DirectorySearcher search = new DirectorySearcher(new DirectoryEntry(), string.Format("(samaccountname={0})", id));
if (search == null)
return id;
if (search.FindOne() == null)
return id;
DirectoryEntry usr = search.FindOne().GetDirectoryEntry();
IADsUser oUsr = (IADsUser)usr.NativeObject;
return string.Format("{0} {1}", usr.Properties["givenname"].Value, usr.Properties["sn"].Value);
However this requires impersonation with an id that's required to be changed every 2 weeks and then updated in the web.config which is often forgotten
Is there any non impersonation code to achieve the same result ?
UPDATE - it's a config tool and it looks up name, email id etc.
I like the service a/c idea
Q - How is it possible to run ( impersonate ) just the AD code with a "service" a/c ? any samples/code ?
how do you impersona

For your particular purpose, a ServiceAccount shall be added to AD;
If you ASP.NET application is for a LAN in your organization, you could simply forget about providing Username and Password and only provide the root domain. This way, Active directory will search for Windows authenticated user instead of using impersonnation (this assumes that the user accessing your application has the rights to perform the tasks provided by your application).
What exactly does your application need to do?
If your application manages user accounts, groups and OU, then you need to use impersonnation only if the user doing these tasks through the application has no rights of managing the AD with her/his regular user account. This, should not happen. So, event for this, if the user has the proper rights, omitting your credentials will only allow AD to search for the current logged on user.

We usually request IT to give us a domain service account. You still need to impersonate, but with a service account, the password will not have to be changed every 2 weeks, and is granted specific rights for the particular function you need it for, so it would mean very low maintenance for you.

I don't think so, because you need to bind to the domain with valid credentials in order to read from active directory.
Think of the username/password as part of a connection string to a database. I'd request a complex username and password from your domain administrator and request that they give it limited login permissions and set the password to never expire. Then store and use those in your Web.config file.

Related

How can I securely ensure the current user belongs to an Active Directory Group?

I am creating a C# Winform Application which will be used in a corporate domain (Windows Active Directory). The app is to behave as the following:
When a user opens the App, the App checks if the current user is part of an Active Directory group.
If it is, the app then allows the user to use the app.
From google searches, I found several ways how to check if a user is part of an Active Directory group.
For example in the link here => How to check if a user belongs to an AD group?
My concern is the security part of this. What if someone spoofs a username and domain. He won't need to know the password to allow access to the app.
Don't do a look up. The SID of every group the user is a member of (recursively) is part of the user's login token. So you can just use WindowsPrincipal.IsInRole(). If you only have the name of the group, you can give it that:
var currentUser = new WindowsPrincipal(WindowsIdentity.GetCurrent());
currentUser.IsInRole("SomeGroup")
That translates the name into the SID and checks the login token for that SID. That requires a network request. If you can give it the SID of the group instead, then you can save that network request:
var groupSid = new SecurityIdentifier("S-1-5-21-blah");
currentUser.IsInRole(groupSid)

how to change the password on an AD user account that is both hidden and expired

If a domain AD user account is hidden * and expired, is there a way to change the password (not reset) in .net / c# ?
The code I have currently is using System.DirectoryServices.AccountManagement and is essentially something like
using (var context = PrincipalContext(ContextType.Domain, server, container)
{
var directoryUser = UserPrincipal.FindByIdentity(context, IdentityType.SamAccountName, username);
directoryUser.ChangePassword(oldPassword, newPassword);
}
This works OK for users that the application service account can find, but some "hidden" users are in OUs that the application service account does not have read permissions to - and hence this fails with a null user.
I thought I would change it so that the PrincipalContext is established with the username and password of the user themselves (since they will have permissions to find themselves) - but often the account is expired by the time they come to change their password and so the FindByIdentity call fails as invalid credentials since the account is expired..
It's kind of a catch-22 where I can't find the user unless I search as the user, but I can't search as the user since they are expired, and I can only unexpire them by getting them to change their password.
If they have access to a workstation they can change their password using the Windows login controls but how to achieve this same level of functionality in c#?
EDIT1: I'm hoping for a solution that does not involve a service account with read-access to the hidden OUs - that would be difficult to achieve for various organization reasons.

Accessing user info from a one way trust

I have two domains, MINE and THEIRS. MINE is my local domain and has a one way trust with THEIRS (using LDAPS port 636), so that MINE trusts THEIRS but THEIRS does not trust MINE. I can add users from THEIRS to groups in MINE, and have users from THEIR log into machines and applications on the MINE network. The trust appears to be working properly.
I am writing a little .Net application (not ASP.Net) to test connectivity over the WAN. We have one app that isn't seeing users from THEIRS in groups in MINE. Other apps, like SharePoint, work fine.
I tried using ASP.Net 4 option with System.DirectoryServices.AccountManagement objects, like PrincipalContext, UserPrincipal, GroupPrincipal, etc. Quick code snippet
PrincipalContext domainContext = GetDomainContext(DomainName, ConnectionPort,
UseSpecifiedCredentials, Credentials);
GroupPrincipal theGroup = GroupPrincipal.FindByIdentity(domainContext,
IdentityType.SamAccountName, GroupName);
PrincipalCollection theUsers = theGroup.Members;
var users = from u in theUsers
select u.Name;
return users.ToArray();
It all works GREAT when I connect directly to MINE. The issue comes in with connecting to THEIRS. Either the 1 way trust of the LDAPS traffic is returning the error:
System.DirectoryServices.Protocols.LdapException: The LDAP server is unavailable.
So I switch to .Net 2 variations using DirectoryEntry, DirectorySearcher, etc. This actually works against THEIRS domain.
List<string> userNames = new List<string>();
string searchString = string.Format("(sAMAccountName={0})", GroupName);
SearchResult result = SearchAD(DomainName, ConnectionPort, searchString);
I can connect directly to the THEIRS domain, using some impersonation in the code.
When I query the groups in MINE, I get back the SID for the users from THEIRS, not a user account.
The following users are a member of testGroup:
CN=S-1-5-21-....,CN=ForeignSecurityPrincipals,DC=MINE,DC=local
CN=S-1-5-21-....,CN=ForeignSecurityPrincipals,DC=MINE,DC=local
I tried the impersonation on this as well, running it as a user from THEIRS but no luck.
How can I get user info from THEIRS when the user is in MINE? Do I have to take the above CN/SID and query THEIRS domain? What am I missing in the .Net 4 stuff?
I assume you have your ASP.NET machine running in MINE.
Your System.DirectoryServices.AccountManagement approach should just work if you make sure you use a domain user account from THEIR domain to run the application. In normal one-way trust configuration (unless you are doing selective authentication trust), the domain user account from THEIR should have permissions to read from both MINE and THEIR.
To make sure you use a domain user from THEIR domain, you can simply set the AppPool identity. Of course, you can use impersonation to do it too.

What are the security permissions required to enumerate users on active directory

System Specs:
Infopath 2007 with c# code-behind
Webservices
Active Directory
I need to get the users name (First Name and Last Name) from active directory but the user appears to not have permissions to read the active directory listings.
What permissions do I need to give the user in order for them to search AD
I am using code like this
SearchResult result;
using (DirectoryEntry de = new DirectoryEntry("LDAP://DC=contoso,DC=com,DC=au"))
{
DirectorySearcher search = new DirectorySearcher(de, (string.Format("(&(objectClass=user)(mailNickname={0}))",this.Application.User.UserName)));
result = search.FindOne();
}
I have considered creating a webservice that gets the information required but that seems like overkill but would get around having to make sure every possible user of the form is required to have the correct permissions
EDIT:
The code that I am trying to execute is infopath code behind. The form itself connects to webservices to retrieve some of its data. as such it is under infopath's security model. The form is fully trusted so it should be fine to execute under the current user context.
My fault for not adding the extra detail.
When you create a new DirectoryEntry without specifying a username and password you're connecting to Active Directory using the credentials of the executing user - in your case probably the local IUSR_...-account on the web server which is the default account used when a new web site is set up in IIS. Because that's a local account you won't be able to access Active Directory.
You have two options:
Create a service account in Active Directory and use that account explicitly, ie DirectoryEntry de = new DirectoryEntry("LDAP://DC=contoso,DC=com,DC=au", "sa-username", "sa-password", AuthenticationTypes.Secure). Of course, passwords in clear text in the code is not a good idea so find a way to encrypt the password.
or
Configure the IIS application pool for your web site (IIS 6+) to run under a domain user account - that way that account is used when connecting to Active Directory.
Any user of the AD should have permissions to browse the AD by default.
You probably just need to change your directory entry to point to the user container like so:
new DirectoryEntry("LDAP://CN=users,DC=contoso,DC=com,DC=au")
Your user container could be another name.
If that does not solve the problem it may be that the application is not actually running as the user. For example, an ASP.NET website would need to be using impersonation in order to query the AD.

How to tie into a domain server's login for program access rights

I need to write a program used internally where different users will have different abilities within the program.
Rather than making users have a new username and password, how do I tie into an existing domain server's login system?
Assume .NET (C#, VB, ASP, etc)
-Adam
For WinForms, use System.Threading.Thread.CurrentPrincipal with the IsInRole() method to check which groups they are a member of. You do need to set the principal policy of the AppDomain to WindowsPrincipal first.
Use this to get the current user name:
private string getWindowsUsername()
{
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
return Thread.CurrentPrincipal.Identity.Name;
}
And then something like this to check a role:
if (Thread.CurrentPrincipal.IsInRole("Domain Users") == true)
{}
In ASP.NET, the thread will belong to IIS, so instead you should
Set the virtual folder or website to require authentication
Get the user name supplied by the browser with Request.ServerVariables("LOGON_USER")
Use the DirectorySearcher class to find the users groups
I would use LDAP
and the DirectorySearcher Class:
http://msdn.microsoft.com/en-us/library/system.directoryservices.directorysearcher.aspx
Assuming this is served through IIS, I would tell IIS to authenticate via the domain, but I would keep authorization (what roles a user is associated with, accessible functionality, etc) within the application itself.
You can retreive the username used to authenticate via
Trim(Request.ServerVariables("LOGON_USER")).Replace("/", "\").Replace("'", "''")
OR
CStr(Session("User")).Substring(CStr(Session("User")).LastIndexOf("\") + 1)

Categories