I am working on authenticating an MVC4 application using Active Directory. Users are assigned to local security groups specific for this application (Local_Group_APP_myApp_Admin).
I am using a custom AuthorizeAttribute. The attribute on top of my action methods is:
[AuthorizeAD(Groups = "Local_Group_APP_myApp_Admin")]
In the custom AuthorizeAttribute class I have:
foreach (var group in groups)
if (userPrincipal.IsMemberOf(context, IdentityType.Name, group))
return true;
}
This would check whether the user is a member of Local_Group_APP_myApp_Admin, which is false (I don't know why). If I get the PARENT (global) group of Local_Group_APP_myApp_Admin, I think IsMemberOf(global_group) would return true.
How to get the parent group of a local group?
Although you have not specified where userPrincipal is set, it seems like your problem is IsMemberOf only returns true if the user is actually a member of that group. If you need to recursively check for group membership you need to do something more like:
using (PrincipalSearchResult<Principal> securityGroups = user.GetAuthorizationGroups())
{
return securityGroups.Any(g => groups.Contains(g.Name));
}
GetAuthorizationGroups returns all security groups the user has membership of.
You can query LDAP to get all the parent groups from a subgroup using the following C#/LDAP query, you can see the full context of the code in this answer, you will need to get your LDAP path correct
DirectorySearcher searcher = new DirectorySearcher(entry, "(&(objectcategory=group)(cn=Local_Group_APP_myApp_Admin))", new string[] { "memberof" });
SearchResult result = searcher.FindOne();
Related
I currently have the following code which successfully gets all Security Groups from AD and adds them into a Check List box:
try
{
Logging.LogMessageToFile("Reading Security Groups from AD.");
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
GroupPrincipal qbeGroup = new GroupPrincipal(ctx);
PrincipalSearcher srch = new PrincipalSearcher(qbeGroup);
foreach (var found in srch.FindAll())
{
lstAdGroups.Items.Clear();
lstAdGroups.Items.Add(found);
}
}
catch (Exception ex)
{
Logging.LogMessageToFile("Unexpected error reading Security Groups from AD: " + ex.Message);
}
My issue is that it currently pulls every Security Group (where ideally I'd only like to only list custom created security groups (eg, exclude any from the Users or Builtin OU's). I can't see if there are any properties against groups to filter 'custom' from out the box. Is this even possible?
PrincipalSearcher can only filter based on attributes that are exposed in properties of the various Principal classes. If you're looking for groups, you're limited to filtering based on the properties of the GroupPrincipal class.
That issues aside, filtering out objects in certain OUs isn't something you can do in a query at all simply because there is no AD attribute that contains the OU that you're allowed to filter on. So there is two ways you can do this:
Do what you're already doing, but in your loop, look at the DistinguishedName property of the result. If it's in an OU you don't like, then just continue;.
You can use DirectorySearcher directly (which is what PrincipalSearcher uses in the background anyway), and filter by the isCriticalSystemObject attribute. That will filter out built-in objects like the Domain Admins and Users groups, etc.
Here is a simple example using DirectorySearcher that just outputs the name of each group:
var searcher = new DirectorySearcher("(&(objectClass=group)(!isCriticalSystemObject=TRUE))");
using (var results = searcher.FindAll()) {
foreach (SearchResult result in results) {
Console.WriteLine(result.Properties["cn"][0]);
}
}
I have the following code. It is supposed to check with the ldap server what roles does a user has and display all of them and delete any role that doesnt exist on the ldap server. Right now it doesnt display "domain users" group as it is the primary group. But i need it to display domain users role as well. I tried including the (primaryGroupID=513) in the filter but that doesnt work as 'directorySearcher.FindOne();' returns null after i add the primaryGroupID to the filter.
I am sure you have done your research as well. I dont believe there is an easy way to access the groups that are set up as primary, or part of the groups that are members of the same group as Domain Users. My account in my AD have 125 groups but only 70 shows up if i query via powershell or DirectoryEntry.
I know that the following code works and pulls all the groups regardless of what type of group it is.
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
UserPrincipal user = (UserPrincipal)Principal.FindByIdentity(ctx, userID);
PrincipalSearchResult<Principal> userGroups = user.GetAuthorizationGroups();
You can access the default group if you get the PrimaryGroupID first.
We document the LDAP Filter that can be used.
And there is also Get-ADPrincipalGroupMembership
This worked flawlessly
`if (results!=null)
{
//find primary group (by default Domain Users)
var User = results.GetDirectoryEntry();
User.RefreshCache(new string[] { "tokenGroups" });
foreach (byte[] resultBytes in User.Properties["tokenGroups"])
{
var SID = new SecurityIdentifier(resultBytes, 0);
var sidSearcher = new DirectorySearcher();
sidSearcher.SearchRoot = directoryEntry;
sidSearcher.Filter = "(objectSid=" + SID.Value + ")";
sidSearcher.PropertiesToLoad.Add("name");
var sidResult = sidSearcher.FindOne();
if (sidResult != null)
{
MemberGroups.Add((string)sidResult.Properties["name"][0]);
}
}`
I was using following code to get all the users from a specific Active Directory group in a specific domain. This code is working fine.
using (var context = new PrincipalContext(ContextType.Domain, "dept.mycomp.net"))
{
using (var group = GroupPrincipal.FindByIdentity(context, "IT Team"))
{
if (group != null)
{
var users = group.GetMembers(true);
foreach (UserPrincipal user in users)
{
Console.WriteLine("Name: " + user.DisplayName);
Console.WriteLine("Network Id: " + user.SamAccountName);
}
}
}
}
I saw there is Entire Directory option in Active Directory Lookup window. So I searched a bit and found following code; this code will get me all the users from Entire Directory root level. This code is also working fine in my case:
var currentForest = Forest.GetCurrentForest();
var gc = currentForest.FindGlobalCatalog();
using (var userSearcher = gc.GetDirectorySearcher())
{
userSearcher.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=" + username + "))";
SearchResult result = userSearcher.FindOne();
}
Question: how would I modify the later code to fetch all the users for a specific group at root level? I would be passing just the GroupName Instead of Domain & Group Name.
The Entire Directory option searches the Global Catalog, rather than just the domain, as it looks like you've found out. The only difference in the search is which port it connects to. Port 389 is the LDAP port, which searches only the domain of the server you're connecting to. Port 3268 is the Global Catalog. A short form for this is using GC:// instead of LDAP://.
If you're working only in a single environment where you know the domain, you can just hard code it. It'll save the network requests of GetCurrentForest() and FindGlobalCatalog().
This is what I mean:
var searcher = new DirectorySearcher(new DirectoryEntry("GC://dept.mycomp.net"));
On to your other question of searching for a specific group: Keep in mind that the Global Catalog searches your AD forest, which can be more than one domain. The names of any object are only enforced unique within the domain, not the forest. So if you search the GC for the name of a group, you can potentially get duplicates. (there could be an "IT Team" group on all of your domains)
But anyway, if we assume you only have one group by that name in your whole forest, this is how you would search for it and get the members:
var groupname = "IT Team";
var members = new List<string>();
using (var searcher = new DirectorySearcher(new DirectoryEntry("GC://dept.mycomp.net"))) {
searcher.Filter = "(&(objectCategory=group)(objectClass=group)(cn=" + groupname + "))";
searher.PropertiesToLoad.Add("member"); //only get the member attribute
using (SearchResult result = searcher.FindOne()) {
foreach (var member in result.Properties["member"]) {
members.Add(member);
}
}
}
When that completes, members will be a list of the distinguishedName of each member. If you want a different attribute (like displayName) then you will need to create a DirectoryEntry for each member and get that attribute.
There are a couple caveats that may or may not be relevant:
There could be groups inside that group. This does not look for members of those groups.
If your domain has a trust with another domain outside your forest, then members from that external domain show up differently. I talked about that in a post I made on my site called What makes a member a member?
This may or may not limit how many members you see to a max of 1000 (if the group has more than 1000 members). I can't remember off hand if that happens with this method. I know it does when reading the 'member' attribute from a DirectoryEntry. If your group isn't that big, then it's not an issue.
To get all groups in Active Directory i have write this code in C#. It works perfectly well as i dont need to pass any servername, OU, DC etc.
UserPrincipal current_user = UserPrincipal.Current;
PrincipalContext current_context = current_user.Context;
PrincipalContext ctx = new PrincipalContext(ContextType.Domain);
GroupPrincipal qbeUser = new GroupPrincipal(ctx);
Principal userOrGroup = qbeUser as Principal;
userOrGroup.Name = "*";
PrincipalSearcher searcher = new PrincipalSearcher(userOrGroup);
List<string> AllGroups = new List<string>();
// enumerate the results - you need to check what kind of principal you get back
foreach (Principal found in searcher.FindAll())
{
// is it a UserPrincipal - do what you need to do with that...
if (found is UserPrincipal)
{
// ......
}
else if (found is GroupPrincipal)
{
AllGroups.Add(found.Name);
//GroupPrincipal gp = found as GroupPrincipal;
//var data = gp.GetMembers();
// if it's a group - do whatever you need to do with a group....
}
}
//return AllGroups;
The problem is that it list too many groups that i dont need like
PerformanceLogUsers, SchemaAdmins, HelpServiceGroups, Telnet Clients and so on.
I only need groups like Administrator, Guests and other user created group. I have read about something like these are special group and etc etc.
Any help in this regard is highly appreciated.
AD doesn't discriminate by group relevance when performing searches. It's either a group or it isn't. However, you can specify whether or not to return security groups or distribution groups, for instance.
How your directory is currently set up, is another matter. If the groups you want and the groups you don't want are both "Security Groups", then it'll pose a problem.
One solution to that would be finding some unique attribute that your relevant groups have in common (or create one) and then filter on the existence of those.
I have a series of applications that all use the same C#, .Net 2.0 code that I've created to check and see if a user is a member of an Active Directory group.
I haven't had any trouble with my code until recently, when I added a user from another, trusted AD domain to one of my AD groups. My question is how can I check to see if a user is a member of an Active Directory group, regardless of their domain. In other words, they may or may not be in the same domain as my group. Below is the code that I have written and used for years to search to see if the user is in an Active Directory group. I'm not sure where I adapted this code from but I'd assume it came from an MSDN article. Also, the solution must be for the .Net 2.0 framework. I have found quite a few answers that may work for this problem in .Net 3.5. Unfortunately, that won't work for my scenario.
//This method takes a user name and the name of an AD Group (role).
//Current implementations of this method do not contain the user's domain
//with userName, because it comes from the Environment.UserName property.
private static bool IsInRole(string userName, string role)
{
try
{
role = role.ToLowerInvariant();
DirectorySearcher ds = new DirectorySearcher(new DirectoryEntry(null));
ds.Filter = "samaccountname=" + userName;
SearchResult sr = ds.FindOne();
DirectoryEntry de = sr.GetDirectoryEntry();
PropertyValueCollection dir = de.Properties["memberOf"];
for (int i = 0; i < dir.Count; ++i)
{
string s = dir[i].ToString().Substring(3);
s = s.Substring(0, s.IndexOf(',')).ToLowerInvariant();
if (s == role)
return true;
}
throw new Exception();
}
catch
{
return false;
}
}
This is not the answer you are waiting for, but I hope it can help.
First ; You suppose you code is working in a domain, but I don't see where it takes care of the user 'principal group'. If you select a group as the 'user principal group', this group is no longer part of the member attribute.
Second ; In my understanding, a way (I hope not the only one, but I'am still looking for) to see, if a user, is present in a group is to 'recusively' look for the user DN in the 'member' attribute of 'group' objects. So, in your case, you may ask your domain and the other domain. You can do that doing ONE search per domain. Here is a sample of such a 'recursive one shoot search' using control :
/* Connection to Active Directory
*/
string sFromWhere = "LDAP://WIN-COMPUTER:389/";
DirectoryEntry deBase = new DirectoryEntry(sFromWhere, "dom\\user", "password");
/* To find all the groups that "user1" is a member of :
* Set the base to the groups container DN; for example root DN (dc=dom,dc=fr)
* Set the scope to subtree
* Use the following filter :
* (member:1.2.840.113556.1.4.1941:=cn=user1,cn=users,DC=x)
*/
DirectorySearcher dsLookFor = new DirectorySearcher(deBase);
dsLookFor.Filter = "(member:1.2.840.113556.1.4.1941:=CN=user1 Users,OU=MonOu,DC=dom,DC=fr)";
dsLookFor.SearchScope = SearchScope.Subtree;
dsLookFor.PropertiesToLoad.Add("cn");
SearchResultCollection srcGroups = dsLookFor.FindAll();
Remark : you can use a more accurate filter to exclude distribution groups for example.
Edited (to answer comments questions) :
First : Are the credentials needed ? I would say no if the request is done from a computer that belongs to the domain or the approved domain.
Second and third : Yes filters are documented by Microsoft in AD Search Filter Syntax. The way I wrote this filter is a deduction from the samples.