Adding user password to an AD with PHP - php

My API (wrote in PHP) needs to register a new user in an AD. It's like the userPassword attribute does not set the password of the user (so he cannot log in).
Things I've tried :
Send the password in plain text : nOK
Send the password with Base64 encoding : nOK
I've read an article (see here) about unicodePwd and the use of LDAPS, but I'm not really sure how to implement this.
I'm actually working with a non-TLS LDAP connection (it's on a local network so I don't need it) on Win2k16 (latest version).
Domain is secureconnect.online (in my code it's .local but don't mind about it).
Here's my code :
public function addUser()
{
// LDAP variables
$ldap_username = $this->ldap_creds['username'];
$ldap_password = $this->ldap_creds['password'];
$ldapuri = $this->ldap_creds['uri'];
// LDAP connection
$link_id = ldap_connect($ldapuri);
if ($link_id) {
ldap_set_option($link_id, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_bind($link_id, $ldap_username, $ldap_password);
$lastname = strtolower($this->validFormData[0]);
$firstname = strtolower($this->validFormData[1]);
$username = $firstname . $lastname;
$display_name = ucwords($firstname) . " " . ucwords($lastname);
$unhashed_pass = $this->validFormData[8];
$encoded_newPassword = "{SHA}" . base64_encode(pack("H*", sha1($unhashed_pass)));
$adduserAD["cn"] = $username;
$adduserAD["givenname"] = ucwords($firstname);
$adduserAD["sn"] = ucwords($lastname);
$adduserAD["sAMAccountName"] = $username;
$adduserAD['userPrincipalName'] = $this->validFormData[2];
$adduserAD["objectClass"] = "user";
$adduserAD["displayname"] = $display_name;
$adduserAD["userPassword"] = $encoded_newPassword;
$adduserAD["userAccountControl"] = "544";
$adduserAD['postalCode'] = $this->validFormData[5];
// Add city
$adduserAD['l'] = $this->validFormData[6];
// Add street address
$adduserAD['streetAddress'] = $this->validFormData[4];
$dn = 'OU=Users-VPN,DC=secureconnect,DC=local';
$base_dn = 'cn=' . $adduserAD['cn'] . ',' . $dn;
$req = ldap_add($link_id, $base_dn, $adduserAD);
if ($req) {
$this->result = $username;
ldap_close($link_id);
} else {
$this->result = '{"error":"Contact Administrator"}';
}
} else {
$this->result = '{"error":"Cannot Connect To Ldap Server"}';
}
return $this->result;
}
Thank's in advance !
EDIT :
So, I've installed an AD LDS with a trusted root certificate. Now when I'm trying to connect with TLS to the server through my API, I'm stuck at this error :
Warning: ldap_start_tls(): Unable to start TLS: Can't contact LDAP server
Here's the code :
/**
* Method used to add and user to an LDAP annuary.
* #return bool|string
*/
public function addUser()
{
// LDAP variables
$ldap_username = $this->ldap_creds['username'];
$ldap_password = $this->ldap_creds['password'];
$ldapuri = $this->ldap_creds['uri'];
// Connexion LDAP
$link_id = ldap_connect($ldapuri);
if ($link_id) {
ldap_set_option($link_id, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_start_tls($link_id);
echo "yeet";
ldap_bind($link_id, $ldap_username, $ldap_password);
Everything beyond this snippet is the same as above.
What should I do ? Do I need to import the certificate to the Web server ?

We have some documentation that explains the process and requirements for using LDAP for Setting and Changing Microsoft Active Directory Passwords
Yes you need encrypted connection
By Default you need to use
UnicodePwd (unless you Enable UserPassword in Microsoft Active
Directory)
And there is a sample in JAVA that shows how we have performed the operation. Usually it works out best to create the user and then set the UnicodePwd value.
We are not real sure why this is the case but issues have been encountered when attempting to both in one operation.
Additionally, often depending on your Microsoft Active Directory settings users are created as disabled and may need to be enabled to be effective.

Related

Set password when creating a new Active Directory user account in PHP

This PHP script creates enabled user accounts in Active Directory without a password. How do I set the password?
<?php
$examplePassword = "34mlrfm$sxkf";
$WinTimestamp = "131196672000000000" //30-09-16 00:00:00
//Create unicode password
function encodePassword($password) {
$password="\"".$password."\"";
$encoded="";
for ($i=0; $i <strlen($password); $i++){ $encoded.="{$password{$i}}\000";}
return $encoded;
}
//Build Active Directory record
$ldaprecord["accountExpires"] = $winTimestamp;
$ldaprecord["UserAccountControl"] = "544"; //544 - Account enabled, require password change
$ldaprecord['userPassword'] = encodePassword($examplePassword);
$ldaprecoed['otherAttributes'] = "Truncated from question";
$ds = ldap_connect($AD_server); // Connect to Active Directory
if ($ds) {
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
$r = ldap_bind($ds, $AD_Auth_User, $AD_Auth_PWD); //Bind
$r = ldap_add($ds,$dn,$ldaprecord); //Create account
ldap_close($ds); //Close connection
}
?>
I've tried different password encoding methoods.
I've also tried inserting the password into $ldaprecord["unicodepwd"]. Which results in "Server is unwilling to perform" error.
I've got it working. You can only set passwords over an SSL connection, thanks #stuartbrand
Either encrypt traffic on 389 using ldap_start_tls() or connect on 636 using $ds = ldap_connect('ldaps://'.$AD_server);
Password should be inserted into the $ldaprecord["unicodepwd"] attribute.

Codeigniter Application with LDAP Authentication

Without codeigniter i am able to use ldap_connect() but in the codeigniter project i want to use ldap connection for authenticating user with their windows username and password. Below is the code which is working perfect without codeigniter.
/******LDAP CONNECTIVITY STARTS HERE*********/
$ldaprdn = $_POST['uname']; // ldap rdn or dn
$ldappass = $_POST['upass']; // associated password
$ldaprdn = $_POST['uname'].'#domain.com';
$ldapconn = ldap_connect("ip") or die("Could not connect to LDAP server."); //our ip
if ($ldapconn) {
$ldapbind = ldap_bind($ldapconn, $ldaprdn, $ldappass);
// verify binding
if ($ldapbind) {
//echo "<pre>";
//print_r($row_login);
//exit;
$_SESSION['appusername']=$_POST['uname'];
$_SESSION['emp_code']=$row_login['emp_code'];
$_SESSION['emp_id']=$row_login['emp_id'];
$_SESSION['emp_name']=$row_login['emp_name'];
$_SESSION['emp_email']=$row_login['emp_email'];
$_SESSION['emp_dept_id']=$row_login['emp_dept_id'];
$_SESSION['emp_dept_name']=$row_login['dept_name'];
$_SESSION['emp_group']=$row_login['emp_group'];
$_SESSION['emp_category']=$row_login['emp_category'];
$_SESSION['finance_app_authority']=$row_login['finance_approval_status'];
$_SESSION['line_eng_status']=$row_login['line_eng_status'];
$_SESSION['line_name']=$row_login['line_name'];
$_SESSION['dept_name']=$row_login['dept_name'];
if($row_login['emp_mod_status']=='Y'){ //if moderator means
$_SESSION['userType']='MOD';
}
else if($row_login['emp_id']==$row_login['dept_hod_id']){ //if HOD means
$_SESSION['userType']='HOD';
}else{ //if normal user means
$_SESSION['userType']='EMP';
}
echo '<script language="javascript">document.location.href="?p=main&m=it-home"</script>';
exit;
}
else{
echo '<div class="man_style" style="width:50%;padding:10px 10px 10px 250px !important;text-align:center;color:red;">Invalid password.</div>';
}
}
All i want is to authenticate user by windows username and password in codeigniter. Suggest me a very simple way please.
I tried Auth_Ldap library but still i am getting an error
LDAP functionality not present. Either load the module ldap php module or use a php with ldap support compiled in.
I have used Auth_Ldap library file. the following config file
Don't know where to give my host ip address
$config['account_suffix'] = '#abcd.com';
$config['base_dn'] = 'DC=domain,DC=local';
$config['domain_controllers'] = array ("server1.domain.local");
$config['ad_username'] = 'administrator';
$config['ad_password'] = 'password';
$config['real_primarygroup'] = true;
$config['use_ssl'] = false;
$config['use_tls'] = false;
$config['recursive_groups'] = true;
/* End of file adldap.php */
/* Location: ./system/application/config/adldap.php */
Your help is appreciated
I did not find the library you want to use (Auth_Ldap), but I found Auth_Ldap. Your config files differ, however. I downloaded the file and in this config you clearly got the ldap_uri, so that would be where your host ip goes I guess.
$config['ldap_uri'] = array('ldap://ldap.mycompany.com:389/');
// $config ['ldap_uri'] = array('ldaps://ldap.mycompany.com:636/'); <-- connect via SSL
$config['use_tls'] = true; // Encrypted without using SSL
$config['search_base'] = 'dc=mycompany,dc=com';
$config['user_search_base'] = array('ou=people,dc=mycompany,dc=com'); // Leave empty to use $config['search_base']
$config['group_search_base'] = array('ou=group,dc=mycompany,dc=com'); // Leave empty to use $config['search_base']
$config['user_object_class'] = 'posixAccount';
$config['group_object_class'] = 'posixGroup';
$config['user_search_filter'] = ''; // Additional search filters to use for user lookups
$config['group_search_filter'] = ''; // Additional search filters to use for group lookups
$config['login_attribute'] = 'uid';
$config['schema_type'] = 'rfc2307'; // Use rfc2307, rfc2307bis, or ad
$config['proxy_user'] = '';
$config['proxy_pass'] = '';
$config['roles'] = array(1 => 'User',
3 => 'Power User',
5 => 'Administrator');
$config['auditlog'] = 'application/logs/audit.log'; // Some place to log attempted logins (separate from message log)
If all else fails and you are comfortable writing your very own library, that might also be an idea.
Update:
I just noticed that the library fails in the _init() function:
private function _init() {
// Verify that the LDAP extension has been loaded/built-in
// No sense continuing if we can't
if (! function_exists('ldap_connect')) {
show_error('LDAP functionality not present. Either load the module ldap php module or use a php with ldap support compiled in.');
log_message('error', 'LDAP functionality not present in php.');
}
I don't actually know why that would fail if the function cleary exists (and works) as you stated previously.
Hello,
Even if the question is more than an year old (and you probably found the answer by now), I will try to give some hints as it might help someone else.
The error you are seeing is because the php_ldap library is not enabled in your php.ini file. So, try to find in the php.ini the line ";extension=php_ldap.dll" and uncomment it by removing the ";" form the beginning.
Note:
If you are using XAMPP (for windows), then after restarting it, PHP will probabbly complain about some dlls missing.
To solve this problem you have to copy the following dll files from your php folder to apache/bin:
libsasl.dll
libeay32.dll
ssleay32.dll (optional; for SSL)

ldap_bind(...) php gives invalid credentials while ldp.exe works

I have serious trouble figuring out which credentials to use to connect to the ad in php.
I can connect successfully using ldp.exe with generic function type and the right domain, user, and password. With any other option set in ldp.exe I can only connect anonymous.
In php I have no chance. I'm not very familiar with ldap, so I am kinda lost here.
Here some php code:
$ldap_host = "ldap://<dc>:389";
$ldap_user = "<username>";
$ldap_pw = "<pw>";
$ldap_domain = "<full domain>";
$connection = ldap_connect($ldap_host) or die("Could not connect to LDAP server.");
//$user = $ldap_user;
$user = $ldap_user."#".$ldap_domain;
//$user = $ldap_user;
//$user = "uid=".$ldap_user;
//$user = $ldap_domain."\\".$ldap_user;
//$user = "User=$ldap_user";
//$user = "cn=".$ldap_user;
//$user = "CN=".$ldap_user.",OU=<someOU>,OU=<someOU>,DC=<DC1>,DC=<DC2>";
ldap_bind($connection, $user, $ldap_pw);
You can see there some combinations I tried. In ldp.exe it is just the $ldap_user in the username field and $ldap_domain in the domain field. Imho atleast the user#domain and domain\user version should work. It is a kerberos domain, if thats important.
Well I don't think there are code errors. But how do I translate the generic function type of ldp.exe into php?
Here the error message to make it easier to find:
Warning: ldap_bind(): Unable to bind to server: Invalid credentials in ...
I would really appreciate some help.
EDIT: In ldp.exe I seem to use the SSPI method. I thought generic picks the method it self so far. Does it have something to do with ldap_sasl_bind() ? The server specifies on connection he is capable of the following:
supportedSASLMechanisms: GSSAPI; GSS-SPNEGO; EXTERNAL; DIGEST-MD5;
While only GSSAPI (SSPI ????) seems to work.
EDIT2: Here some other output of ldp.exe after an successful authentication:
res = ldap_bind_s(ld, NULL, &NtAuthIdentity, 1158); // v.3
{NtAuthIdentity: User='<username>'; Pwd= <unavailable>; domain = '<full domain'.}
Authenticated as dn:'<username>'.
Try specifying the port as well into a variable
$ldapPort = 389;
I would ignore the host part and just try connecting to your server (you have it as domain) Check to see if your ldap bind is working
// Handle login requests
$ds = ldap_connect($ldapServer, $ldapPort);
if (ldap_bind($ds, $user, $password)) {
// Successful auth
$_SESSION['lastactivity'] = time();
$_SESSION['username'] = $user;
$_SESSION['password'] = $password;
return $ds;
} else {
// Auth failed
header("Location: failpage.php?fail=1"); //bad credentials
exit;
}
Also for calling all the attributes, try http://blog.uta.edu/jthardy/2007/08/08/obtaining-user-information-from-ldap-using-php/

PHP ldap bind issue

I've been looking at a couple of guides (and the PHP manual) trying to validate AD users on an intranet site I'm about to make. This is the first time I've used ldap_connect, and I haven't had the best of luck.
Could anyone look at my code and see what I'm missing?
Thanks.
<?php
$user = "08jf1";
$password = "pass";
// Active Directory server
$ldap_host = "10.43.48.5";
// Active Directory DN
$ldap_dn = "OU=CSE-W7,OU=Students-W7,DC=server,DC=local";
// Domain, for purposes of constructing $user
$ldap_usr_domain = "#server.local";
// Connect to AD host
$ldapconn = ldap_connect("10.43.48.5");
if ($ldapconn) {
$bind = ldap_bind($ldap_host, $ldap_dn, $user . $ldap_usr_domain, $password);
if ($bind) {
echo "Verified user";
//$_SESSION['username'] = $session_username;
//$_SESSION['password'] = $session_password;
} else {
echo "User does not exist";
}
}
?>
Edit: I can confirm ldap is enabled though phpinfo!
Is that syntax of ldap_bind correct?. Isn't it ldap_bind($ldapconn,$rdn,$password) ?
Binding may need a elevated privilege or authbind wrapper. Refer to authbind for ldap. LDAP AuthBind
Take a look at this very simple example: How to use LDAP Active Directory Authentication with PHP

Change Password in Active Directory using LDAP/PHP/IIS/SSL

First of all, this may be less of a programming question and more of a how do I configure LDAPS question, but here goes...
Background Info:
I have two Windows 2008 R2 servers. One is a domain controller (DC) with Active Directory (AD) that I want to communicate with via LDAP. This one is named TestBox.TestDomain.local. The other server is running IIS, PHP (with ldap and openssl), and mySQL.
What is/isn't working:
I can successfully connect to the DC unsecured over port 389 and read/write data to AD. What I can't do is change or set user passwords since this requires a secure connection using LDAPS (LDAP w/ SSL) over port 636.
What I need help with:
I have tried installing Active Directory Certificate Services (AD CS) and configuring the DC to act as a Certificate Authority (CA) using information found here: http://technet.microsoft.com/en-us/library/cc770357(WS.10).aspx but no matter what I try I can't get a connection over LDAPS to work.
Sample Code:
Creating the LDAP Connection
function ldapConnect(){
$ip = "100.200.300.400"; // WAN IP goes here;
$ldap_url = "ldap://$ip";
$ldaps_url = "ldaps://$ip";
$ldap_domain = 'testdomain.local';
$ldap_dn = "dc=testdomain,dc=local";
// Unsecure - WORKS
$ldap_conn = ldap_connect( $ldap_url ) or die("Could not connect to LDAP server ($ldap_url)");
//alternate connection method
//$ldap_conn=ldap_connect( $ip, 389 ) or die("Could not connect to LDAP server (IP: $ip, PORT: 389)");
// Secure - DOESN'T WORK
//$ldap_conn = ldap_connect( $ldaps_url ) or die("Could not connect to LDAP server ($ldaps_url)");
//alternate connection method
//$ldap_conn=ldap_connect( $ip, 636 ) or die("Could not connect to LDAP server (IP: $ip, PORT: 636)");
ldap_set_option($ds, LDAP_OPT_PROTOCOL_VERSION, 3);
ldap_set_option($ds, LDAP_OPT_REFERRALS, 0);
$username = "AdminUser";
$password = "AdminPass";
// bind using admin username and password
// could also use dn... ie. CN=Administrator,CN=Users,DC=TestDomain,DC=local
$result = ldap_bind($ldap_conn, "$username#$ldap_domain", $password ) or die("<br>Error: Couldn't bind to server using supplied credentials!");
if($result){
return $ldap_conn;
}else{
die("<br>Error: Couldn't bind to server using supplied credentials!");
}
}
Adding a New User to Active Directory
function ldapAddUser($ldap_conn, $ou_dn, $firstName, $lastName, $username, $pwdtxt, $email){
$dn = "CN=$firstName $lastName,".$ou_dn;
## Create Unicode password
$newPassword = "\"" . $pwdtxt . "\"";
$len = strlen($newPassword);
$newPassw = "";
for($i=0;$i<$len;$i++) {
$newPassw .= "{$newPassword{$i}}\000";
}
$ldaprecord['cn'] = $firstName." ".$lastName;
$ldaprecord['displayName'] = $firstName." ".$lastName;
$ldaprecord['name'] = $firstName." ".$lastName;
$ldaprecord['givenName'] = $firstName;
$ldaprecord['sn'] = $lastName;
$ldaprecord['mail'] = $email;
$ldaprecord['objectclass'] = array("top","person","organizationalPerson","user");
$ldaprecord["sAMAccountName"] = $username;
//$ldaprecord["unicodepwd"] = $newPassw;
$ldaprecord["UserAccountControl"] = "544";
$r = ldap_add($ldap_conn, $dn, $ldaprecord);
// set password .. not sure if I need to base64 encode or not
$encodedPass = array('userpassword' => base64_encode($newPassw));
//$encodedPass = array('unicodepwd' => $newPassw);
echo "Change password ";
if(ldap_mod_replace ($ldap_conn, $dn, $encodedPass)){
echo "succeded";
}else{
echo "failed";
}
}
Just two pieces of advice:
During the AD CS setup, in the Specify Setup Type page, click Enterprise, and then click Next.
AD service is supposed to take himself his own certificate, but if it works like in Windows server 2003, you must reboot the server to make it work. Perhaps just stop and restart the service in W2K8 R2.
Afer that, you can just try to build a certificate and install it on the AD service account, like you can find it done with ADAM.
Did you create a certificate request for the secure Ldap with the correct OIDs?
here's my inf file:
[Version]
Signature="$Windows NT$
[NewRequest]
Subject = "CN=my-server.blahblah.com" ; must be the FQDN of host
Exportable = TRUE ; TRUE = Private key is exportable
KeyLength = 4096 ; Common key sizes: 512, 1024, 2048,
; 4096, 8192, 16384
KeySpec = 1 ; Key Exchange
KeyUsage = 0xF8 ; Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment, Key Agreement
MachineKeySet = True
ProviderName = "Microsoft RSA SChannel Cryptographic Provider"
ProviderType = 12
RequestType = CMC
; Omit entire section if CA is an enterprise CA
[EnhancedKeyUsageExtension]
OID=1.3.6.1.5.5.8.2.2
OID=1.3.6.1.5.5.7.3.1
OID=1.3.6.1.5.5.7.3.2
OID=1.3.6.1.5.5.7.3.3
OID=1.3.6.1.5.5.7.3.4
OID=1.3.6.1.5.5.7.3.5
OID=1.3.6.1.5.5.7.3.6
OID=1.3.6.1.5.5.7.3.7
OID=1.3.6.1.5.5.7.3.8
OID=1.3.6.1.5.5.7.3.9
OID=1.3.6.1.4.1.311.10.3.4
OID=1.3.6.1.4.1.311.54.1.2
[RequestAttributes]
CertificateTemplate = MySpecialTemplate ;Omit line if CA is a stand-alone CA
SAN="my-server.blahblah.com"
YOU SHOULD MAKE A TEMPLATE ON THE CA USING THE 2003 (NOT ALL MICROSOFT PRODUCTS CAN UTILIZE 2008 TEMPLATES -- I KNOW STUPID HUH) COPY IT FROM DOMAIN CONTROLLER AND THROW THE KITCHEN SINK AT THE OIDS
Just make your connection as trust all. Then it will no longer need certificates. Check out javax.net.sslTrustManager.

Categories