Generic LDAP base for search? - winapi

I'm writing some C++/Win32 code to search for a user in an LDAP directory (really I need to validate a username/password is correct, and then verify group membership). I have the username, so I'm hoping something like the following will work:
(&(objectCategory=person)(objectClass=user)(uid={username}))
When I call ldap_search with this search/filter, I have to provide a starting base (node/OU/whatever) to search. But I don't know where to start the search -- all I have is the username. Is there anyway to specify the root of the tree that will work with OpenLDAP, Active Directory, Netscape LDAP, etc, etc?
Also, anyone that can answer that could probably help with this: Is the uid attribute universally supported, or do I need to search on a different attribute depending on what brand of LDAP server I'm talking to? (I've seen references to people needing to search on uid, CN and even SAMAccountName).

Regarding your first question about generically retrieving a search base:
Every LDAP directory server (conforming to the LDAP protocol I think) exposes some operational thingies under a node called RootDSE. One of the things you can retrieve through RootDSE are the namingContexts which essentially can tell you what the different trees are hosted on this server.
So you can retrieve a top-level search base for your username-search. Please be aware: some LDAP (OpenLDAP for example) servers can host multiple trees so you have to come up with a solution when multiple naming contexts are found.
The RootDSE can be retrieved by querying the server for the DN "" (empty string) and specifiyng that you want to get all the operational attributes as well. Just some example for an OpenLDAP server:
ldapsearch -H ldap://ldap.mydomain.com -x -s base -b "" +
# note the + returns operational attributes
This should return something similar to that shown below (from OpenLDAP 2.4.8) - the values in parentheses are added explanations and are not returned by the server:
dn:
structuralObjectClass: OpenLDAProotDSE
configContext: cn=config
namingContexts: dc=example,dc=com
namingContexts: dc=example,dc=net
monitorContext: cn=Monitor
supportedControl: 1.3.6.1.4.1.4203.1.9.1.1 (Contentsync RFC 4530)
[...]
supportedExtension: 1.3.6.1.4.1.4203.1.11.1 (ModifyPassword RFC3088)
[...]
supportedFeatures: 1.3.6.1.1.14 (Modify-Increment RFC4525)
[...]
supportedLDAPVersion: 3
supportedSASLMechanisms: NTLM
[...]
entryDN:
subschemaSubentry: cn=Subschema
(from http://www.zytrax.com/books/ldap/ch3/#operational)
Regarding your second question about the availability of the uid attribute:
I don't think that you should rely on this one as it strongly depends on the schema used for storing user data (although most user-schema-classes will have a uid attribute I think). But that depends on the flexibility you want to put into your program. Perhaps the best way would be to make the user-filter-string configurable by the end-user (you could even do this with the search base which would have some performance advantages (no need to search the whole tree when users are only located in a small subtree and no need to query the RootDSE)).

I would not rely on uid being the proper search attribute for the user entries in LDAP. Many companies will only guarantee the employeeID as being unique within the LDAP DIT.

You need to define what container to start searching in. So this would be something like
"LDAP://" + _ADSPath + ":" + _ADSPort + "/" + _ADSRootContainer
where _ADSPath is the server hostname/ip; _ADSPort is the port number (usually 389 by default); and _ADSRootContainer is the rest of the path to the container (like ou=Users.
The path would depend on the implementation you are searching against. You can start up higher than the container holding the users and set the parameters on the search object to use a multi-level search. But it will be much slower.

Related

How can I encrypt the parameters of a panel in the same way as Genexus?

We need to encrypt a string in the same way that Genexus (17U10 and csharp if it's important) encrypts the parameters of a panel using the site key.
To better understand, the first is the url with unencrypted parameters, the second is the same url with parameters encrypted via site key
http://localhost/TestVersione17U10.NETFrameworkEnvironment/webpanel3.aspx?par1=hello
http://localhost/TestVersione17U10.NETFrameworkEnvironment/webpanel3.aspx?ROndRLvw5t80mViNc0wdKO7XYc-OgWL61k9lDimrqI0
Reading in the wiki, I believe that genexus uses the key stored in the application.key file and uses the twofish algorithm.
7E2E22D26FF2989E2444852A85E57867
This is the key I have in the file, I tried in every way to get the second string starting from the first, but without success.
The native Encrypt64 method gave no results, the generated string is different.
I also noticed that the same parameters are encrypted differently when I call another panel, so I believe it somehow uses the panel name as well.
( webpanel2.aspx?mY8XtkZ-3eBJKsDIFk-zX3DP2PuQC2LHIkqwFtE1CZw )
What am I doing wrong? Is the key wrong? Do you use any other way to encrypt other than Encrypt64?
I’m not sure what you really want to implement. I mean, do you want storage this link? Do you need it in order to call from a “non GX application”?
Anyway, as you said, object name is included in the algorithm to URL encryption.
This algorithm is not available as a “function” to be used by GX developers directly. However, there are two ways to do something like that in Genexus:
To use “link” function. https://wiki.genexus.com/commwiki/servlet/wiki?8444,Link%20Function
To use non standard functions. Suppose you have “webpanel3.aspx par1=hello,par2=world” then the code could be something like:
&GXKey = GetSiteKey()
&GXEncryptionTmp = "webpanel3.aspx"+UrlEncode("hello”) + "," + UrlEncode("world")
&EncryptedParms= "?" + UriEncrypt64( &GXEncryptionTmp + CheckSum(&GXEncryptionTmp, 6), &GXKey))
Note: You must enable “non standard functions” (https://wiki.genexus.com/commwiki/servlet/wiki?8013,Standard%20Functions%20property%20at%20Object%20level)
If you need to call from a non GX application, there are to options:
To use a GX generated program as “proxy”. This object receive not encrypted parms and returns the encrypted URL or directly encrypt the parameters and call the corresponding object
To explore object generated in order to mimic that code in your solution/code. This includes exploring GXClassses (i.e. https://github.com/genexuslabs/DotNetClasses)

Fulltext-index in Neo4J in 2.0

Is there a way to
create a fulltext-index with a given lucene-analyzer on a certain node-Type (and certain fields only)
to get this index updated automatically when a node of the given type is created / deleted
query this index over the Cypher- oder the REST-API
I am using the Cypher/REST-Interface (and of course the shell, etc.) of the server not the embedded version.
If this is not available (which I guess): Is something like this on the roadmap?
Thank you in advance!
Short answer: no
Little bit longer answer:
You can write a KernelExtension adding a TransactionEventHandler that amends the fields to be fulltext indexed to a manual index (aka legacy index).
The code should be wrapped into an unmanaged extension and deployed to the server.
There something similar implemented within https://github.com/sarmbruster/neo4j-uuid.
The contents of the legacy index can be accessed using start n=node:myindex('lucene query string') in Cypher

Get a list of Active Directory Users along with their Full Name and Email

I need to retrieve a list of Active Directory users and their attributes using Delphi 2010.
I've seen a few similar questions on SO (e.g. Delphi - Find primary email address for an Active Directory user), but they all seem to require the user name before any additional information can be retrieved.
I had written an article for [The Delphi Magazine] way back when..... if you have access to a backlog of those magazines, it's in issue no. 62 (October 2000) - unfortunately, it seems those back issues aren't available for purchase anymore :-(
It's too long of an article and a code sample to post here.... basically it's about wrapping the IDirectorySearch interface in a nicer Delphi-like shell. You pass in a base container where to search, you define an LDAP filter, and you define a set of attributes you're interested in - then you search and get back basically an enumerator for the results, which you can get one by one.
In the end, I discovered TJvObjectPickerDialog, part of JVCL. It wraps the Windows Select Object dialog and does everything I need with very little coding. Just set the required properties and call execute. The selected user objects are returned along with the attributes that you set in the 'Attributes' property.

Query all the users in a system with LDAP

I am using ruby's net/ldap library for this problem but in reality the driver language shouldn't really matter. I need to find a way to be able to get all the users from a system and find out which users do not have emails assigned to the account. Is it possible?
I can connect to and even create new records through LDAP, and can return queries by using wildcard entries to filter results.
given i create a filter to find the cn that begins with three 9's:
filter = Net::LDAP::Filter.eq("cn", "999*")
#connection.search(:base => "cn=Manager, dc=foo, dc=bar, dc=biz",
:filter => filter)
then my result count might be 42.
given i create the same filter but request only 1 nine, the query fails and returns false
filter = Net::LDAP::Filter.eq("cn", "9*")
#connection.search(:base => "cn=Manager, dc=foo, dc=bar, dc=biz",
:filter => filter)
and this is the same if I request just "cn", "*" which to me should say "give me all the cn's out there.
".
So the short answer to the question is that it all depends on how your schema is setup. If you are setting up an LDAP schema, you need to have several groups of records with various cn (common name) identifiers, eg cn=activeUsers and cn=inactiveUsers which will allow you to query down the list much deeper than in my situation.
I think that you have an issue with time limit set on search operations at the LDAP server.
If you have a really big search that takes much time, the LDAP server returns an error 'Time limit exceeded' and no data.
Ruby-Ldap in such a case raises an exception LDAP::ResultError. I don't know how Net-Ldap behaves however.
Try to raise the time limit at your LDAP server or use a tighter search filter such as '(&(cn=9*)(active=TRUE))'. Substitute here 'active=TRUE' with your criteria for active users.

How to quickly find a sharepoint document library by id?

Given the SPList.ID and a site collection (or an SPWeb with subwebs), how do I quickly find the document library with the given ID?
I can recursively enumerate through all webs and perform a web.Lists[guid] on each one of them, but there might be thousands of subwebs in my case, and I'm looking for a realtime solution.
If there is no way to do this quickly, any other suggestions on how to uniquely identify a document library? I could store the full path (url), but the identification will be publicly visible and I don't feel very comfortable giving away our exact SharePoint document structure like that. Should I resort to maintaining a manual ID <-> library mapping in a separate list?
I vote for the manual ID -> URL pair matching in a top-level, well-known list that's visible only to the elevated privileges account.
Since you are storing the ListID somewhere, you may also store the WebId. Lists are opened by the context SPWeb always, so if you go to:
http://toplevel/_layouts/ListGeneralSettings.aspx?ID={GUID1} // OK
http://toplevel/sub1/_layouts/ListGeneralSettings.aspx?ID={GUID1} // Wont Work (same Guid)
Having the WebId and ListId you can simply:
using(SPWeb subweb = (new SPSite("http://url")).OpenWeb(new Guid("{000...}")))
{
SPList list = subweb.Lists.GetList(new Guid("{111...}"), true);
// list logic
}
MS does not support this :)...
But take a look at this for giggles: http://weblogs.sqlteam.com/jhermiz/archive/2007/08/15/60288.aspx
If you have MOSS Search available, then it might help, depending on the lag you have between these lists getting created and needing to search for them. You could probably map list id as a managed property and do a quick search for list objects with the id in question.
For lots of classes of problems it seems like search is the fastest way to rip through huge sets of data. In fact if this approach worked for you, you really wouldn't even need to know the site collection up front. Don't have access to any of my MOSS environments at the moment, so can't verify this will work though.

Resources