I'm trying to use LDAP to authenticate against the company Active Directory. ADExplorer shows me that the directory is set up in the manner:
Active Directory Explorer
-- MyCompany.com
+- DC=MyCompany, DC=com
+- OU=Domain Controllers
+- OU=MyCompany Locations
+- OU=BR
+- OU=CA
+- OU=DE
|+- OU=Munich
|+- OU=MyTown
||+- OU=Users & Computers
|||+- OU=Users
||||+- CN=Firstname1 Lastname1
||||+- CN=Firstname2 Lastname2
When I select a particular user, myself for example, I see the AD path is in the form below.
OU=Users,OU=Users & Computers,OU=MyTown,OU=DE,OU=MyCompany
Locations,DC=MyCompany,DC=com
I set up the LDAP options in my application's config.php as follows:
$ldap_base_dn_ar[0]['attribute_name'] = 'ou';
$ldap_base_dn_ar[0]['attribute_value'] = 'Users';
$ldap_base_dn_ar[1]['attribute_name'] = 'ou';
$ldap_base_dn_ar[1]['attribute_value'] = 'Users & Computers';
$ldap_base_dn_ar[2]['attribute_name'] = 'ou';
$ldap_base_dn_ar[2]['attribute_value'] = 'MyTown';
$ldap_base_dn_ar[3]['attribute_name'] = 'ou';
$ldap_base_dn_ar[3]['attribute_value'] = 'DE';
$ldap_base_dn_ar[4]['attribute_name'] = 'ou';
$ldap_base_dn_ar[4]['attribute_value'] = 'MyCompany Locations';
$ldap_base_dn_ar[5]['attribute_name'] = 'dc';
$ldap_base_dn_ar[5]['attribute_value'] = 'MyCompany';
$ldap_base_dn_ar[6]['attribute_name'] = 'dc';
$ldap_base_dn_ar[6]['attribute_value'] = 'com';
This works but I suspect that it will only work for users in MyTown and country.
How would I change this to allow LDAP authentication from any town in any country?
From Gabriel Luci's comments:
You say "I suspect" - have you test that? Maybe it already works the way you want.
I don't have a foreign login at the moment. I'll get one set up or get someone to test it.
But you should only have to specify OU=MyCompany Locations since everything is under that.
$ldap_base_dn_ar[0]['attribute_name'] = 'ou';
$ldap_base_dn_ar[0]['attribute_value'] = 'MyCompany Locations';
$ldap_base_dn_ar[1]['attribute_name'] = 'dc';
$ldap_base_dn_ar[1]['attribute_value'] = 'MyCompany';
$ldap_base_dn_ar[2]['attribute_name'] = 'dc';
$ldap_base_dn_ar[2]['attribute_value'] = 'com';
If I cut the LDAP options down as shown above authentication fails.
Related
This question already has an answer here:
Appengine - Upgrading from standard DB to NDB - ReferenceProperties
(1 answer)
Closed 6 years ago.
I have an old gae app that uses db.model. I understand that I should migrate to ndb.model. Is there an easy way or must I make many changes?
My code is fairly large and I have an old model that is db.model that I use to build index and search. Should I keep the old model and make a new ndb model or try and change the old model?
Some of the variables in the model are
cities = db.ListProperty(db.Key) #ndb.KeyProperty(repeated=True)
regions = db.ListProperty(db.Key) #ndb.KeyProperty(repeated=True)
blobs = db.ListProperty(db.BlobKey) #ndb.BlobProperty(repeated=True)
primary_image = blobstore.BlobReferenceProperty()
usr = db.ReferenceProperty() # ndb_model.KeyProperty()
hasimages = db.BooleanProperty(default=False,
verbose_name='has_images')
userID = db.StringProperty(verbose_name='User ID')
integer_price = db.IntegerProperty()
ip = ndb.StringProperty(verbose_name='ip')
ipcountry = db.StringProperty(indexed=False, verbose_name='origin')
tags = db.ListProperty(db.Category)
category = db.CategoryProperty(verbose_name='Category')
title = db.StringProperty(verbose_name='title') # required
user = db.UserProperty(verbose_name='userid')
im = db.IMProperty(verbose_name='nickname') # optional, xmpp
city = db.StringProperty() # postaladdress should work instead
region = db.StringProperty() # postaladdress should work instead
url = db.StringProperty(verbose_name='url')
geopt = db.GeoPtProperty(verbose_name='geopt')
text = db.TextProperty(verbose_name='text')
It shouldn't be particularly complex, and can be done incrementally, as you can mix db and ndb code in the same binary. See DB to NDB Client Library Migration.
I'm using Location module (particularly its Location CCK part) with Drupal 7. Added location field 'field_location' to User (as an example of hosting entity), and initialized location values for test users in user edit interface. However, I'm unable to access location data of the current user:
global $user;
$user_id = $user->uid;
$loc = $user->field_location;
or:
$wrapper = entity_metadata_wrapper('user', $user_id);
$loc = $wrapper->field_location;
The statements with $loc don't work for object and wrapper (while both user object and wrapper are initialized successfully). Same for:
$loc = $wrapper->field_location[0];
$loc = $wrapper->field_location->raw();
I've read a number of posts on this topic, however haven't found a workable solution, would appreciate insights on this.
The location module, by itself, does not support the Entity API/Metadata Wrapper out-of-box. However, it is packaged with the Location Entity module, which will enable it for entity api support.
Once enabled,
$wrapper = entity_metadata_wrapper('user', $user_id);
$loc = $wrapper->field_location->value();
Works as expected.
If you want a quick workaround, you can also do:
$user_wrapper = entity_metadata_wrapper('user', $user_id);
$raw_user = $user_wrapper->raw();
$loc = $raw_user->field_location['und'][0];
This isn't elegant, but it's a solution without additional modules. Take your pick.
I'm trying to write an LDAP query which will discover if a user is a member of a group which matches a wildcard query and I'm trying to use the LDAP_MATCHING_RULE_IN_CHAIN OID to do this. I'm basically following example 2 on this page:
http://support.microsoft.com/kb/914828
I've found that this method works well within a domain i.e. if user1 is in group1 and group1 is in group2 then I can write a query matching "*2" and the LDAP query will find the nested relationship and match the user against the group.
However, now I've been asked to support relationships between domains in the same forest. So now I've got:
user1 is a member of group1 in domain 1
group1 in domain 1 is a member of group2 in domain 2
And I want to be able to match user1 against group2.... I can't work out how to make LDAP_MATCHING_RULE_IN_CHAIN do this:
I've tried setting the base of the query to the following:
Domain 1, but this just returns groups in domain 1
The parent domain of domain 1 and domain 2, but this returns no results.
The GC, found by querying "rootDSE" property but this just returns groups inside the domain 1 (which is the GC server)
Anyone know how I can make this work?
As far as I understand, one way of doing that is :
From the RootDSE, look for the configuration NamingContext.
In the configuration NamingContext looking for objects of class crossRef with an attribute nETBIOSName existing.
From these entries use the algorithm you are discribing by using dnsRoot and nCName attributs. A working forest DNS allows you to join a domain controler of dnsRoot. nCName allows to search from the root.
Be careful to do this as a member of the enterpreise administrators group.
Here is an example of the code.
/* Retreiving RootDSE
*/
string ldapBase = "LDAP://WM2008R2ENT:389/";
string sFromWhere = ldapBase + "rootDSE";
DirectoryEntry root = new DirectoryEntry(sFromWhere, "dom\\jpb", "PWD");
string configurationNamingContext = root.Properties["configurationNamingContext"][0].ToString();
/* Retreiving the root of all the domains
*/
sFromWhere = ldapBase + configurationNamingContext;
DirectoryEntry deBase = new DirectoryEntry(sFromWhere, "dom\\jpb", "PWD");
DirectorySearcher dsLookForDomain = new DirectorySearcher(deBase);
dsLookForDomain.Filter = "(&(objectClass=crossRef)(nETBIOSName=*))";
dsLookForDomain.SearchScope = SearchScope.Subtree;
dsLookForDomain.PropertiesToLoad.Add("nCName");
dsLookForDomain.PropertiesToLoad.Add("dnsRoot");
SearchResultCollection srcDomains = dsLookForDomain.FindAll();
foreach (SearchResult aSRDomain in srcDomains)
{
/* For each root look for the groups containing my user
*/
string nCName = aSRDomain.Properties["nCName"][0].ToString();
string dnsRoot = aSRDomain.Properties["dnsRoot"][0].ToString();
/* 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)
*/
/* Connection to Active Directory
*/
sFromWhere = "LDAP://" + dnsRoot + "/" + nCName;
deBase = new DirectoryEntry(sFromWhere, "dom\\jpb", "PWD");
DirectorySearcher dsLookFor = new DirectorySearcher(deBase);
// you cancomplete the filter here (&(member:1.2.840.113556.1.4.1941:=CN=user1 Users,OU=MonOu,DC=dom,DC=fr)(cn=*2)
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();
foreach (SearchResult srcGroup in srcGroups)
{
Console.WriteLine("{0}", srcGroup.Path);
}
}
This is just a proof of concept, you have to complete with :
using using(){} form for disposing DirectoryEntry objects
Exception management
Edited (2011-10-18 13:25)
Your comment about the way you solve the problem can be found in a method given in System.DirectoryServices.AccountManagement Namespace. It's a kind of recursive solution. This time, I test with a user belonging to group1 (in an other domain) which belongs to group2 (in a third domain) and it seems to work.
/* Retreiving a principal context
*/
Console.WriteLine("Retreiving a principal context");
PrincipalContext domainContext = new PrincipalContext(ContextType.Domain, "WM2008R2ENT:389", "dc=dom,dc=fr", "jpb", "PWD");
/* Look for all the groups a user belongs to
*/
UserPrincipal aUser = UserPrincipal.FindByIdentity(domainContext, "user1");
PrincipalSearchResult<Principal> a = aUser.GetAuthorizationGroups();
foreach (GroupPrincipal gTmp in a)
{
Console.WriteLine(gTmp.Name);
}
Is there a simple way to resolve the Active Directory path of a Domain name in Active Directory?
E.g. your user account might be SITE\Username or DEPARTMENT\Username but the actual path of the domain SITE might be site.company.com or DEPARTMENT might be dep.company.com etc
I'm trying to find a way of turning DEPARTMENT into DC=dep,DC=company,DC=com etc for searching correctly in Active Directory...
What you probably have is a company with one forrest (company.com) and a couple of child domains (SITE and DEPARTMENT in your case). The SITE- and DEPARTMENT-bits are the NetBIOS representations of the domains. Is not very common that they differ from the corresponding DNS names but it is possible. Just make sure we're not talking about OU:s and "physical" Active Directory sites.
Assuming the above, here are a couple of options:
The following assumes that your application is running under an account with "forrest-wide read access" (the ability to access your different domains):
using System.DirectoryServices.ActiveDirectory;
// ...
DirectoryContext directoryContext
= new DirectoryContext(DirectoryContextType.Domain, "DEPARTMENT");
Domain domain = Domain.GetDomain(directoryContext);
String domainName = domain.Name;
String domainComponent = "DC=" + domainName.Replace(".", ",DC=");
Console.WriteLine(domainComponent);
(I haven't found a "System.DirectoryServices-built-in" way to transform domain.company.com to DC=domain,DC=company,DC=com but the simple string manipulation above should do the trick.)
If you're using a non-forrest-wide account (or if DEPARTMENT and SITE are not domains in the same forrest but in themselves separate forrests), then you'll have to maintain a list of usernames and passwords to use depending on the "DEPARTMENT" or "SITE"-strings:
// if(domainNetBios == "DEPARMENT")...
DirectoryContext directoryContext
= new DirectoryContext(DirectoryContextType.Domain,
"DEPARTMENT",
"UserInDEPARTMENT",
"PassForUserInDEPARTMENT");
If you're not willing to bind to the different forrests/domains to get the domain name/component you could try something along the lines of:
IPAddress[] addresses = Dns.GetHostAddresses("DEPARTMENT");
IPHostEntry host = Dns.GetHostEntry(addresses[0]);
Int32 dotIndex = host.HostName.IndexOf('.');
String domain =
host.HostName.Substring(dotIndex + 1, host.HostName.Length - dotIndex - 1);
Console.WriteLine(domain);
But the above assumes that the NETBios-name is the same as the first part of the DNS-name and that DNS resolution is working correctly. What we're doing above is to query for a list of domain controllers then removing the hostnames from the DNS-names. Not a particularly clean option...
I've got an asp application running but i want to search the Active Directory.
i am using vb (visual web developer 2008)
how do i search the active directory for a given user?
ie: user enters login name in text box, clicks submit. active directory is searched on-click for this user. when found user information is displayed .
Thanks
What version of the .NET framework can you use? Searching and looking up stuff in AD has become extremely easy in .NET 3.5 - see this great MSDN article by Ethan Wilanski and Joe Kaplan on using the security principals API for that.
If you're not on .NET 3.5 yet, you'll have to use the DirectorySearcher class and set up the search filters as you need. Getting the LDAP filter right is probably the biggest obstacle.
Robbie Allen also has two great intro article on System.DirectoryServices programming:
- Part 1
- Part 2
There are some really good resources at http://www.directoryprogramming.net (Joe Kaplan's site - he's a Microsoft Active Directory MVP), and Richard Mueller has some great reference excel sheets on what properties are available for each of the ADSI providers, and what they mean, and how their LDAP name is - see http://www.rlmueller.net.
Marc
EDIT: Ok- here's the .NET 2.0 / 3.0 approach:
// set the search root - the AD container to search from
DirectoryEntry searchRoot = new DirectoryEntry("LDAP://dc=yourdomain,dc=com");
// create directory searcher
DirectorySearcher ds = new DirectorySearcher(searchRoot);
ds.SearchScope = SearchScope.Subtree;
// set the properties to load in the search results
// the fewer you load, the better your performance
ds.PropertiesToLoad.Add("cn");
ds.PropertiesToLoad.Add("sn");
ds.PropertiesToLoad.Add("givenName");
ds.PropertiesToLoad.Add("mail");
// set the filter - here I'm using objectCategory since this attribute is
// single-valued and indexed --> much better than objectClass in performance
// the "anr" is the "ambiguous name resolution" property which basically
// searches for all normally interesting name properties
ds.Filter = "(&(objectCategory=person)(anr=user-name-here))";
// get the result collection
SearchResultCollection src = ds.FindAll();
// iterate over the results
foreach (SearchResult sr in src)
{
// do whatever you need to do with the search result
// I'm extracting the properties I specified in the PropertiesToLoad
// mind you - a property might not be set in AD and thus would
// be NULL here (e.g. not included in the Properties collection)
// also, all result properties are really multi-valued, so you need
// to do this trickery to get the first of the values returned
string surname = string.Empty;
if (sr.Properties.Contains("sn"))
{
surname = sr.Properties["sn"][0].ToString();
}
string givenName = string.Empty;
if (sr.Properties.Contains("givenName"))
{
givenName = sr.Properties["givenName"][0].ToString();
}
string email = string.Empty;
if (sr.Properties.Contains("mail"))
{
email = sr.Properties["mail"][0].ToString();
}
Console.WriteLine("Name: {0} {1} / Mail: {2}", givenName, surname, email);
}
Hope this helps!
Marc