Perl Net::LDAP - Fetch DN without Search? - perl

I have the DN of the LDAP entry. I know I could search for it: Doing something like this:
my $search = $ldap->search(
base => $dn,
scope => "base",
filter => "(objectclass=*)",
);
But, I don't need to do a search. I have the DN. I simply want to pull up the DN entry and do my operations directly on that. Something like this:
my $dn_entry = $ldap->get( $dn );
Is there a method to get the DN entry from the DN string itself, or do you have to search for the entry even if you know the DN itself?

Using LDAP, clients must always search or use an extended operation to get data. If you're interested in all the attributes associated with an entry, and the DN is known, use the following parameters in a search request:
baseObject: the DN that is known
search scope: base
filter: either (&) or (objectClass=*)
the list of attributes to be returned. Some APIs use * for all user attributes and + for all operational attributes.

What it sounds like you are saying is that you have stored the "Distinguished Name" (a string) rather than the DN entry (a Net::LDAP::Entry object). If this is the case, I believe you have to create a new Net::LDAP::Entry object from the DN. The documentation indicates that you can apply operations directly to such an object without synchronizing with the server, but this won't supply all the data for the given DN. If you need the server's data, you need to get it via $ldap->search(...).
Have you considered using the Net::LDAP::LDIF mechanism for storing DN data locally?

Related

Is it possible displaying ldap folder structure with Perl?

I will retrieve user informations from a LDAP server. Customer sent me following 3 data:
LDAP Server IP
Username to authenticate
Password to authenticate
This is the 1st time I am working with LDAP so I studied on it. I see that I must use some parameters like cn, dc, ou. Should not customer give this info either? Or customer's info is enough and can I find these parameters by a code displaying folder structure?
The structure you want to see is called the directory tree and is made of LDAP "entries" (not folders).
You should be able to collect entries from your directory provided that the credentials you've been given are sufficient. For that you need a client library, you can use Perl LDAP.
Using that library you would do something like :
use Net::LDAP;
# Init connection and bind to the directory.
$ldap = Net::LDAP->new('ldaphost.example.com') or die "$#";
$mesg = $ldap->bind ($binddn, password => $password);
# Perform a search on the whole tree below (and including) the base object.
$mesg = $ldap->search(base => $basedn);
# Handle error
$mesg->code && die $mesg->error;
# Display results
foreach $entry ($mesg->entries) { $entry->dump; }
$mesg = $ldap->unbind;
The code above just print entries to stdout ($entry->dump).
$binddn is the dn to authenticate with. If you've been given a simple username that is not a dn, like 'username' instead of something like uid=username,dc=example,dc=com, it would probably mean that you are dealing with Active Directory. In this case you can try to bind with a binddn that corresponds to the following pattern : 'username#example.com'.
basedn is the dn of the base object entry, the search is performed on the whole tree below (and including) the base object. You will have to specify a valid base dn.
You can try to guess which base dn to use. Domain components (dc) usually match the FQDN but it is not guaranteed it results in a valid base dn (e.g. 'ldaphost.example.com' would give 'dc=example,dc=com'). However you can query the server for rootDSE information and retrieve the namingContexts (or defaultNamingContext if any) and use one of them as the base dn :
$ldap->search(base => '', attrs => 'namingContexts');
That said, if you really want to display the directory tree, you have better to go with an LDAP explorer like Apache Directory Studio.
Note that LDAP is not limited to storing information in strict "tree" structures, it just have to respects a Directory Information Tree (DIT) nomenclature.

REST Resource route naming for get and ResourceByID and ResourceByName

I am trying to write 2 Rest GET methods.
Get user by Id
Get user by userName.
I need to know if there is any resource naming convention for this. Both my id and username are strings.
I came up with:
/api/{v}/users/{userid}
/api/{v}/users/username/{username}
However, 2) doesn't seem correct and if I change 2) to /api/{v}/users/{username}, I am mapping to 1) as both id and username are strings. Or is it considered acceptable to use /api/{v}/userbyName/{username}?
How should I name my resource route in case 2) ?
First of all: https://vimeo.com/17785736 (15 minutes which will solve all your questions)
And what is unique? Is the username unique or only the id or both are unique?
There is a simple rule for all that:
/collection/item
However, 2) doesn't seem correct and if I change 2) to /api/{v}/users/{username}, I am mapping to 1) as both id and username are strings.
If your item can be identified with an id and also with an unique username - it doesn't matter if it's the username or the id - simply look for both (of course your backend needs to handle that) and retrieve it.
According to your needs this would be correct:
/api/{v}/users/{userid}
/api/{v}/users/{username}
but I would choose only to use: /api/{v}/users/{userid} and filter by username only with a query parameter (description for that down there below)
Also will I break any rules if I come up with
/api/{v}/userbyName/{username}
Yes - /api/{v}/userbyName/{username} will break the rule about /collection/item because userByName is clearly not a collection it would be a function - but with a real restful thinking api there is no function in the path.
Another way to get the user by name would be using a filter/query paramter - so the ID will be available for the PathParameter and the username only as filter. which than would look like this:
/api/{v}/users/?username={username}
This also don't break any rules - because the query parameter simply filters the whole collection and retrieves only the one where username = username.
How should I name my resource route in case 2) ?
Your 2) will break a rule - so I can't/won't suggest you a way to do it like this.
Have a look at this: https://vimeo.com/17785736 this simple presentation will help you a lot about understanding rest.
Why would you go this way?
Ever had a look at a javascript framework like - let's say ember. (Ember Rest-Adapter). If you follow the idea described up there and maybe also have a look at the json format used by ember and their rest adapter - you can make your frontend developer speed up their process and save a lot of money + time.
By REST you send back links, which can contain URI templates. For example: /api/{v}/users/{userid} in your case, where v and userid are template variables. Since the URI structure does not matter from a client perspective you can use whatever structure you want. Ofc. it is more convenient to use nice and short URIs, because it is easier to write the routing with them.
According to the URI standard the path contains the hierarchical while the query contains the non-hierarchical part of the URI, but this is just a loose constraint, in practice ppl use both one.
/api/{v}/users/name/{username}
/api/{v}/users/name:{username}
/api/{v}/users?name="{username}"
Ofc. you can use a custom convention, for example I use the following:
I don't use plural resource name by collections
I end collection path with slash
I use slash by reducing a collection to sub-collections or individual items
I don't use slash to give the value of a variable in the path, I use colon instead
I use as few variables and as short URI as I can
I use query by reducing a collection to sub-collections especially by defining complex filters with logical operators
So in you case my solution would be
/api/{v}/user/
/api/{v}/user/name:{username}
/api/{v}/user/{userid}
and
/api/{v}/user/?firstName="John"
/api/{v}/user/?firstName="John|Susan"&birthYear="1980-2005"
or
/api/{v}/user/firstName:John/
/api/{v}/user/firstName:John|Susan/birthYear:1980-2005/
etc...
But that's just my own set of constraints.
Each resource should have a unique URI.
GET /users/7
{
"id": 7,
"username": "jsmith",
"country": "USA"
}
Finding the user(s) that satisfy a certain predicate should be done with query parameters.
GET /users?username=jsmith
[
"/users/7"
]

LDAP binding in Perl when OU is unknown

Is there a way to successfully bind while leaving out one of the files in the bind search base string? I don't always know what $site is for a user and if I leave it out the binding fails. Can I have something like OU=*,
$ldapSearchBase = "OU=$site,OU=xxxx,OU=xxxx,DC=$globalLocation,DC=companyName,DC=com";
If I leave the site out I get. it works if I put in my correct site
The wrong password was supplied or the SASL credentials could not be processed
LDAP binds require you to have a single unique distinguished name plus the appropriate credentials (user/pass, SSL, etc.). Your bind will always fail if your DN is not unique.
You might want to try splitting your base DN and varying whatever $site is:
my $ldapSearchBase = "OU=user,OU=accounts,DC=$globalLocation,DC=companyName,DC=com";
my $ldapSite = "OU=$site";
my $bindString = $ldapSearch . "," . $ldapSearchBase;
Use the first container as search base:
$ldapSearchBase = "DC=$globalLocation,DC=companyName,DC=com";

How to do a search-by-DN using Net::LDAP

I want to check if a given DN exists in the LDAP directory, using Perl and Net::LDAP. So, I figured I'd do something like this:
my $dn = 'uid=foo,ou=bar,ou=baz';
$ldap->search(base => $dn, scope => 'base', attrs => ['dn']);
However, that results in a Bad filter error. I can get it to work by adding filter => '(objectClass=*)', but that seems a little klugey.
Is this how I'm supposed to do this, or have I missed something? I'm new to Net::LDAP.
An LDAP client must supply a valid search filter to a search request. Try using (&) for the filter. Note that some broken directory servers do not accept the legal filter (&). If your server is broken in this way, use the present filter (objectClass=*) instead.

LDAP group membership filter used in RT3

I am trying to setup LDAP authentication to an Active Directory server for an RT3 site.
I think that there is an error in the LDAP authentication module, but I really do not understand what the filter is trying to do. See RT/Authen/ExternalAuth/LDAP.pm line 126:
$ldap_msg = $ldap->search( base => $group,
filter => $filter,
attrs => \#attrs,
scope => 'base');
There is a config file that specifies the group, group_attr and group_attr_value.
Group is passed as $group, and the filter is created from a group_attr=group string. In my case group_attr = present and the memberOf line comes back with CN=ITAdmins,CN=Builtin,DC=SPGLOBAL,DC=local and the filter becomes Filter: (present=CN=ITAdmins,CN=Builtin,DC=SPGLOBAL,DC=local) and Attrs: dn.
This is invalid for a filter, but can any one who knows a bit more about this see what is meant to be happening?
Thanks for posting the link to the code, that makes it much simpler to understand.
So the model is, authentitcate with username and password, then $group, if defined means check that they are a member of a group to let them in.
$group should be a full LDAP DN, so cn=AccessGroup,ou=Groups,dc=myDomain,dc=com or the like.
$group_attr_val should be member, memberOf, or maybe Member, depending on whatever the member attribute is in your target LDAP directory.
So I think your issue is that group-attr=present is probably wrong and should be as simple as member instead.