I'm surprised there's so few examples on this out there. I basically need to do a user/pass authentication against Active Directory. I'm able to initialize a connection to active directory, but it always gives me an "Invalid Credentials" error. I'm wondering if I'm passing it something wrong. This is my first attempt with LDAP. For that matter, I'm open to another (well documented perhaps) solution.
#include <iostream>
#include <stdio.h>
#define LDAP_SERVER "ldap://hq.mydomain.local/"
#include <ldap.h>
int main( int argc, char** argv )
{
LDAP *ld;
int version( LDAP_VERSION3 );
int rc;
char bind_dn[100];
berval creds;
berval* serverCreds;
if( ldap_initialize( &ld, LDAP_SERVER ) ) {
std::cerr << "Error initializing ldap..." << std::endl;
return 1;
}
ldap_set_option( ld, LDAP_OPT_PROTOCOL_VERSION, &version );
creds.bv_val = "password";
creds.bv_len = strlen("password");
rc = ldap_sasl_bind_s( ld, "sAMAccountName=MYDOMAIN\\UserName,dc=mydomain,dc=local", "GSSAPI", &creds, NULL, NULL, &serverCreds );
if ( rc != LDAP_SUCCESS ) {
std::cerr << "ERROR: " << ldap_err2string( rc ) << std::endl;
return 1;
} else {
std::cout << "Success." << std::endl;
}
return 0;
}
EDIT:
I wanted to make sure everything is okay on the server side, so did some tests with ldapsearch. It did not work at first, but I finally got it (with ldapsearch, anyway).
ldapsearch -D [email protected] -H "ldap://hq.mydomain.local:389" -b "ou=Development,ou=Domain Users,dc=mydomain,dc=local" -W "sAMAccountName=first.last"
Maybe not the best way. For starters, the key is the -D argument, and passing sAMAccountName at the end. I'm not going to have the common name - only the windows login name, and their password. The above command will show a user his info, if the password passes.
The caveat (I think) is that ldap_sasl_bind_s() has no equivalent of setting the -D (binddn) flag. Looking at this question/answer it looks like ldap_interactive_bind_s() might, but it's a bit more involved, as I have to pass a call back.
With the example above where I set a password, but no binddn/username of any kind, who does it assume I'm trying to authenticate as?
sAMAccountName=MYDOMAIN\UserName,dc=mydomain,dc=local
This format of username is incorrect. You do not need to specify sAMAccountName
in your username and don't need to specify dc
unless you're using Distinguished Name
. You have few options for username.
CN=Jeff Smith,OU=Sales,DC=Fabrikam,DC=Com
jsmith
"Fabrikam\jeffsmith".
Having said that, I'm not certain if the username is the only issue you're experiencing. I have not run your code locally.
Although this answer may not directly answer your question, since I have not tested this code in Linux machine, it could give you an idea or put you in a right direction. I will not be surprised if this method is Windows specific only.
According to MSDN there're few methods
you can use to authenticate a user.
The ADsOpenObject function binds to an ADSI object using explicit user name and password credentials.
This method is accepting the following parameters:
HRESULT ADsOpenObject(
_In_ LPCWSTR lpszPathName,
_In_ LPCWSTR lpszUserName,
_In_ LPCWSTR lpszPassword,
_In_ DWORD dwReserved,
_In_ REFIID riid,
_Out_ VOID **ppObject
);
Using this method you can bind to object in Active Directory by specifying username
and password
.
If the bind is successful, the return code is S_OK
, otherwise you'll get different error messages.
I don't write programs in C++
on a daily basis. I typically work with Active Directory
and Active Directory Lightweight Services
in a C#
world. But this sample code I wrote, shows you how to call ADsOpenObject
method to bind to an ADSI object using specified credentials. In your case, just authenticate
.
#include <iostream>
#include "activeds.h"
using namespace std;
int main(int argc, char* argv[])
{
HRESULT hr;
IADsContainer *pCont;
IDispatch *pDisp = NULL;
IADs *pUser;
CoInitialize(NULL);
hr = ADsOpenObject( L"LDAP://yourserver",
L"username",
L"password",
ADS_FAST_BIND, //authentication option
IID_IADs,
(void**) &pUser);
if (SUCCEEDED(hr))
{
cout << "Successfully authenticated";
}
else
cout << "Incorrect username or password";
return hr;
}
Depending on your setup, you might have to tweak ADS_AUTHENTICATION_ENUM
. I suggest you install SSL Certificate and use ADS_USE_SSL
binding. Dealing with passwords without SSL in AD, can be nightmare.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With